I'm trying to validate my JPA Entity with #Valid like this:
public static void persist(#Valid Object o)
It worked fine for a while but now it stopped working and I'm not sure why. I tried to do it manually inside the persist method, and it works as expected:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(o);
if (!constraintViolations.isEmpty()) {
throw new ConstraintViolationException(constraintViolations);
}
What could be happening or how can I debug this?
Method Validations is only available starting in bean validation v 1.1 (e.g. hibernate validator 5.x impl) which is part of Java EE 7 only. On top of that to have it working without extra specific BV code your method must be part of a component which is integrated with bean validation (eg. CDI Beans, JAX-RS Resource). Your custom code works because you do not use method validation but rather BV constraints which are defined directly on your object.
Won't work on arbitrary services. In Jersey it will only work for resource methods. So validate the incoming DTO in your resource method.
#POST
public Response post(#Valid SomeDTO dto) {}
See more at Bean Validation Support
UPDATE
So to answer the OP's comment about how we can make it work on arbitrary services, I created a small project that you can plug and play into your application.
You can find it on GitHub (jersey-hk2-validate).
Please look at the tests in the project. You will find a complete JPA example in there also.
Usage
Clone, build, and add it your Maven project
public interface ServiceContract {
void save(Model model);
}
public class ServiceContractImpl implements ServiceContract, Validatable {
#Override
public void save(#Valid Model model) {}
}
Then use the ValidationFeature to bind the service
ValidationFeature feature = new ValidationFeature.Builder()
.addSingletonClass(ServiceContractImpl.class, ServiceContract.class).build();
ResourceConfig config = new ResourceConfig();
config.register(feature);
The key point is to make your service implementation implement Validatable.
The details of the implementation are in the README. But the gist of it is that it makes use of HK2 AOP. So your services will need to be managed by HK2 for it to work. That is what the ValidationFeature does for you.
Related
I am trying to implement a project using jobrunr. I have a use case where a service I have written should be triggered once the maximum retries are done for a job. I tried achieving the same using this answer as reference. The filter logic is triggered once a job fails but the dependency I include (which has my logic) is returning a null point exception(java.lang.NullPointerException: Cannot invoke "com.project.service.ScheduleHistoryService.someFunc()" because "this.service" is null). I am able to inject the same service file using #Autowire in my other components.
What am I doing wrong here?
I am using jobrunr version 5.1.4.
Attached is a screenshot of the sample code:enter image description here
Injecting services in the filters is only possible in the Pro version of JobRunr.
My hack / workaround for this is injecting the Service in the regarding Configuration and passing it to the constructor of a CustomRetryFilter:
#Configuration
public class JobRunrConfig {
#Bean
public BackgroundJobServer backgroundJobServer(
StorageProvider storageProvider, JsonMapper jobRunrJsonMapper, JobActivator jobActivator, BackgroundJobServerConfiguration backgroundJobServerConfiguration, JobRunrProperties properties,
ApplicationEventPublisher applicationEventPublisher) {
BackgroundJobServer backgroundJobServer = new BackgroundJobServer(
storageProvider, jobRunrJsonMapper, jobActivator, backgroundJobServerConfiguration);
backgroundJobServer.setJobFilters(
Collections.singletonList(
new CustomRetryFilter(
applicationEventPublisher,
properties.getJobs().getDefaultNumberOfRetries(),
properties.getJobs().getRetryBackOffTimeSeed())));
backgroundJobServer.start();
return backgroundJobServer;
}
}
I am doing a spring boot rest application with a custom exception mapping. The exception mapping is irrelevant, but I wanted to use hibernate validator in version 4 ((because I have to use java validation api version 1.0).
Now I am initializing the validators in #configuration class:
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Bean
MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(validator);
return processor;
}
And I create a resource:
#Path("/validation")
#Produces("application/json")
#Validated
public interface ValidationTestResource {
#POST
#Path("/test")
#Validated
public void translatedAndMappedException(#RequestBody #Valid
ValidationTestDto testDto);
}
}
The resource works. And the validation works. But whenever I violate the constraints on ValidationTestDto I get an exception. However this is org.hibernate.validator.method.MethodConstraintViolationException and it only specified which method and which parameter failed to validate (translatedAndMappedException, argument testDto). This makes it kind of useless to return the violated field list, as such list is not present.
But If I use hibernate-validator version 5+ I get a proper javax.validation.ConstraintViolationException and I can extract a full list of fields that were not validated.
The question is:
1.If I am simply doing something wrong, and Hibernate validator 4 is like that.
2.If I can use something from spring to validate and forget about hibernate-validator that would do it properly?
Spring provides its own validation interfaces, so you can try using those directly. The documentation is here. You can use a BindingResult to see the details of the validation errors that are produced.
I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.
I've been going through the Play! 2.1 example to setup a basic login system following the ZenTasks example. Where I get stuck is the JavaForms part. I want to validate the login request using an instance of an auth service that is provided via Guice DI.
I'm following Play20 Sample. This example uses a static authenticate() method to run the authentication when form validation is requested after form submission. Any thoughts on how to perform this validation step in a non-static scope?
Note: I have looked at the Play! Authenticate plugin as well as the SecureSocial plugin, however those projects are overkill for what I want to do right now. Also, I am interested in a general solution for allowing non-static validation in JavaForms.
Edit:
It seems there is some confusion about what I am asking for here. What I am hoping to find is an alternate way to perform the validation step of the form submission that is sent by a Play! framework Form.form() generated form. Currently it requires that a validate() method be called on an instance of a POJO which is not created through the DI framework. This results in static references being required to access authorization services etc...
Edit 2:
The current solution I am working with is this:
public static class AuthServiceFormReference {
#Inject
public static Provider<AuthService> authService;
}
// In my auth module configure()
//...
requestStaticInjection(AuthController.AuthServiceFormReference.class);
//...
public static class Login {
#Required
public String email;
#Required
public String password;
public String validate(){
if(AuthServiceFormReference.authService.get().authenticateAdmin(email, password) == null) {
return "Invalid user or password";
}
return null;
}
}
It's an okay workaround, but it still relies on static injection :(
Play Framework does not offer Dependency Injection out of the box. However you can integrate it with Guice or Spring. As a lazy developer you could also create a Singleton for the service, or make it a plugin (as it probably needs to prepare work on application startup anyways). Then you can get a reference to your plugin -- Play.application().plugin(AuthPlugin.class).
In this particular case you can do a database lookup in the validate methods, e.g. User u = User.find.where().eq("username", username).eq("password`,password).findUnique();
if (u == null)
return "Error.";
else
return null;
So this isn't so much about Play Framework, but Java programming in general.
Assuming you use Spring, you can do it like in any other Java program:
#Configurable
public class MyModel {
#Autowired
transient MyService myService;
public String validate() { ... }
}
The #Configurable annotation makes the class capable of dependency injection. The transient qualifier makes sure the field doesn't get picked up as a field to save into a database.
Spring works fine with Play 2.0/2.1 in one of my projects. I don't consider dependency injection in model objects aesthetically pleasing, but if you need it you can use it.
I'm looking to see whether or not the following is even possible, as all preliminary searches haven't turned back anything to indicate either way.
I'd like to use Hibernate's Validator annotations to validate bean methods, and I would like to use some AOP framework (Spring, AOP Alliance, AspectJ, etc.) to intercept methods annotated with a subset of the Hibernate Validator annotations (#NotNull, #NotEmpty, #Email, etc.); I then want AOP advice to run when they are encountered.
Is this possible to do? If so, I am having a tough time visualizing how the code would work. Using Spring AOP's MethodInterceptor interface as an example:
First, the bean using Hibernate Validator:
public class SomeBean
{
private String data;
// Hibernate Validator annotation specifying that "data" cannot be an empty
// string.
#NotEmpty
public String getData() { ... } // etc.
}
Then, some code using that bean:
public void someMethod()
{
SomeBean oBean = new SomeBean();
// Validation should fail because we specified that "data" cannot be empty.
oBean.setData("");
}
Next, the AOP advice to be ran when Hibernate Validator-annotated methods are encountered.
public class ValidationInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation invocation)
{
// Here's where we would use Hibernate's validator classes.
// My code example here is wrong, but it gets the point across.
Class targetClass = invocation.getClass(); // Should give me SomeBean.class
ClassValidator<targetClass> oValidator= new ClassValidator<targetClass>();
// Here I need to get a reference to the instance of the offending
// SomeBean object whose data has been set to empty...not sure how!
SomeBean oOffendingBean = getTheBadBeanSomehow();
InvalidValue[] badVals = oValidator.getInvalidValues(oOffendingBean);
}
}
So, not only am I choking on what the Spring AOP (pointcut definitions, etc.) configuration would look like to intercept the Hibernate Validator annotations I want, and not only do I not fully grasp how to implement the actual advice (e.g. how to instantiate the offending SomeBean from inside the advice as I mention above in the comments), but I'm not even sure if this solution is possible, Spring or otherwise.
Thanks in advance for some gentle "nudges" in the right direction!
You might be interested in the method validation feature introduced with Hibernate Validator 4.2 which provides support for validating method parameters and return values.
You then might use Seam Validation which integrates this functionality with CDI. If you want to use method validation together with Spring you could have a look this project on GitHub which shows how to integrate the method validation functionality with Spring AOP (disclaimer: I'm the author of this project as well as of Seam Validation).
To make your example working you would have to annote the parameter of the setter method with #NotEmpty like this:
public class SomeBean {
private String data;
#NotEmpty
public String getData() { return data; }
public void setData(#NotEmpty String data) { this.data = data; }
}