My question is similar to Resteasy Bean Validation Not Being Invoked. The solutions there don't work, though.
I'm using Resteasy 3.0.9.Final with resteasy-validator-provider-11 in my pom. I'm launching the whole thing using a custom Jetty class.
Weirdly, validation is working fine on #PathParams, but not on beans.
#POST
#Path("/foo/{myParam}")
public Message post(MyBean myBean, #PathParam("myParam") #Size(min=5) String myParam) {
return new Message("bean:" + myBean.toString());
}
public static class MyBean {
#NotNull
public String myStr;
#Max(value = 3)
public int myInt;
public String toString() {
return myStr + myInt;
}
}
In this case, the #Size constraint on myParam is working fine. But the #NotNull and #Max constraints in MyBean are not getting invoked.
Am I missing an annotation somewhere?
Here's one more clue. My logs include these entries:
2014-12-30 12:16:56 org.hibernate.validator.internal.util.Version 6446 INFO HV000001: Hibernate Validator 5.0.1.Final
2014-12-30 12:16:56 org.jboss.resteasy.plugins.validation.AbstractValidatorContextResolver 6477 INFO Unable to find CDI supporting ValidatorFactory. Using default ValidatorFactory
I believe, but not 100% sure, that the issue is that you're missing #Valid on the MyBean parameter. I would also recommend to make it a separate class, rather than a static class.
Per the spec, validation constraints on methods where the object is a complex object need to have the parameter annotated #Valid to ensure that the constraints are cascaded.
Related
I need to assure data migration using mongock.
The #ChangeUnit class holds the logic for migration. It has a field annotated with #Value which is always null, even though I properly initialized in application.properties:
mongock.migration-scan-package=my.package
login-secret=test
Then the MigrationConfiguration looks as follows:
#ChangeUnit(id = "test", order = "001", author = "test")
#RequiredArgsConstructor
#Configuration
public class InitUsersChangeLog {
private final MyService service;
private final MongoTemplate template;
#Value("${login-secret}")
private String LOGIN;
#Execution
public void initUser() {
service.create(User.builder().login(LOGIN).build());
}
}
Main class:
#EnableMongock
#SpringBootApplication
public class MailServiceApplication {...}
My assumption is that this value is not injected properly into the MongockConfiguration bean. I tried to configure the bean manually (without using mongock.migration-scan-package=my.package) in the properties, but with no success.
As Mongock currently doesn't support #Value annotation you can try to use getProperty method from Environment bean. Environment bean can be injected same as other beans using constructor or Lombok annotations.
You want to change this:
#Value("your.key.property")
to that:
private final Environment env;
public void method(){
env.getProperty("your.key.property")
}
Mongock currently no supports #value injection via field o method parameter. We will provide that in a future minor release within version 5, but we can't give you dates, yet.
Extending MichalJ's answer, which is absolutely valid. I would like to add that the changeUnits are not retrieved by Mongock via Springboot, they are processed by Mongock independently. So the annotation #Configuration, #Component, etc. won't be taken into account and they could even be damaging.
Related to that, this code won't work, at least not in a near future:
#Value("${login-secret}")
private String LOGIN;
First, as said, Mongock doesn't support value currently, but the first approach will require the constructor parameter to have that #Value("${login-secret}"), not at the field level.
Suppose a simple Spring Boot #Component like this one:
#Component
#Data
#EnableScheduling
#ConfigurationProperties(prefix = "demo")
public class DemoClass {
private String aString;
private Long aLong;
#Scheduled(fixedDelayString = "${demo.delay}")
void getSomething() {
System.out.println("aString = " + aString);
System.out.println("aLong = " + aLong.toString());
}
}
It will not start throwing
ConfigurationPropertiesBindException: Error creating bean with name 'demoClass': Could not bind properties to 'DemoClass'
All you need to fix is a getSomething method name. Just rename it to putSomething for example.
I've lost three hours debugging Spring Boot sources and found it: Spring tries to bind Bean property named Something. And the exception occurs.
I know it's a weird practice to name methods starting with get if it's not a getter, but is it mentioned somewhere in Spring Docs? Does it say something about guessing properties names from method names?
Yes Spring uses the JavaBeans standard to process the configuration properties POJO, as explained here:
Such arrangement relies on a default empty constructor and getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC.
I have a servlet that does validation on XML files based on the address of the person contained in it. The validation is specific to each state, so I have several implementations of my validator, but I don't know which one to use until the request is parsed each time.
I am using Spring, and right now I am getting the correct validator with the following:
Validator validator = applicationContext.getBean(this.state + "Validator");
This seems to break some of the inversion of control. I thought about moving this to a factory class that essentially does the same thing, but abstracts it to a factory:
#Component
public class ValidatorFactory {
#Autowired
ApplicationContext applicationContext;
public Validator getValidator(String state) {
return applicationContext.getBean(state + "Validator");
}
}
It seems like there should be a better way to get the correct bean at runtime without using getBean(). Does anyone have any suggestions?
You can use a Map :
#Component
public class ValidatorFactory {
#Autowired
Map<String,Validator> validators;
public Validator getValidator(String state) {
return validators.get(state + "Validator");
}
}
You can pre-populate the map with the required beans throughs Spring.
I'm trying to implement a #Restricted annotation, to secure controller methods in a way that users can only access them, when they are logged in and have a certain role. I'm on Tomcat 7 using JSF and CDI, so no EJB. The interceptor gets called as long as the annotation interface does not specify any parameters. As soon as I add a #Nonbinding Role value() default Role.ADMIN; parameter, neither the interceptor nor the controller method execute. No errors or exceptions either. Here is my code, I really don't know what's wrong with it:
Annotation:
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
public #interface Restricted {
#Nonbinding Role value() default Role.ADMIN; // ###
}
Interceptor:
#Interceptor
#Restricted
public class RoleBasedRestrictingInterceptor implements Serializable {
#Inject
ISecurityManager security;
#AroundInvoke
public Object intercept(final InvocationContext ctx) throws Exception {
final Restricted annotation = ctx.getClass().getAnnotation(Restricted.class);
log.info("Intercepted, required role is: {}", annotation.value()); // ###
log.info("User is logged in: {}", security.isLoggedIn());
return ctx.proceed();
}
}
Controller:
#Named("manageUsers")
#SessionScoped
public class ManageUsersBacking extends implements Serializable {
#Restricted(Role.ADMIN) // ###
public void testRestricted() {
log.info("testRestricted()");
}
}
The ### occurrences mark what has to be changed or removed to make it work again. The interceptor is properly defined in WEB-INF/beans.xml, since it works without the role parameter in my annotation.
16:04:33.772 [http-apr-8080-exec-11] INFO c.m.s.RoleBasedRestrictingInterceptor - User is logged in: true
16:04:33.772 [http-apr-8080-exec-11] INFO c.m.c.admin.ManageUsersBacking - testRestricted()
Today I revisited this particular problem and noticed it had nothing to do with CDI:
ctx.getClass().getAnnotation(Restricted.class)
Obviously, there is no class level annotation in my example. So getAnnotation() returns null. Instead I should have used the following:
ctx.getMethod().getAnnotation(Restricted.class)
Though I don't know why there where no exceptions whatsoever. Maybe some other things were going on, that I can no longer reproduce because I migrated my application to TomEE.
if you switch to TomEE you'll don't need to depend (maven) on implementations, just api (use org.apache.openejb:javaee-api:6.0-4 with a provided scope
It sounds like you have things setup correct (beans.xml and interceptor). Which CDI implementation are you using? If you're using Tomcat have you looked at using TomEE?
Is JSR-303 also intended for method parameter validation?
If so, is there any example on the web? The biggest challenge I'm facing is how to get a validator within each method. With Spring 3, doesn't it mean that I'd have to inject virtually every class with a LocalValidatorFactoryBean?
Thanks!
Method level validation will be supported in the upcoming version 4.2 of JSR 303's reference implementation Hibernate Validator.
As pointed out in the previous answer this will allow constraint annotations (built-in as well as custom defined types) to be specified at method parameters and return values to specify pre- and post-conditions for a method's invocation.
Note that HV will only deal with the actual validation of method calls not with triggering such a validation. Validation invocation could be done using AOP or other method interception facilities such as JDK's dynamic proxies.
The JIRA issue for this is HV-347 [1], so you might want to add yourself as watcher to this issue.
[1] http://opensource.atlassian.com/projects/hibernate/browse/HV-347
The javadocs for each of the JSR 303 annotations tells the following:
#Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})
See, PARAMETER is there. So, yes, it's technically possible.
Here's an example:
public void method(#NotNull String parameter) {
// ...
}
I'm however not sure how that integrates with Spring since I don't use it. You could just give it a try.
In Spring 3.1.0 you can use #Validated annotation to activate validation on a pojo.
Create an interface for the pojo class an put this annotation over it, then add your validation annotations in the methods definitions. ( the interface is required because Spring will create a proxy class using the interface as definition )
#Validated
public interface PojoClass {
public #NotNull String doSomething(#NotEmpty String input);
}
your pojo :
public class PojoClassImpl implements PojoClass {
public String doSomething(String input) {
return "";
}
}
Starting from a standard spring web application with active validation, remember to add in your spring configuration this bean declaration:
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
This sounds like a use case for AOP (AspectJ). Write a pointcut for methods that are annotated with javax.validation.constraints.*, inject a validator into the aspect (probably using Spring) and use a #Before or #Around advice to perform the validation before method execution.
Read AspectJ in Action for reference.
You can use jcabi-aspects (I'm a developer), which integrates JSR 303 with AspectJ. Actual validation is done by one of JSR 303 implementations, which you will have to add to class path, like Hibernate Validator, or Apache BVal.