2

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?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
diogocarmo
  • 960
  • 1
  • 11
  • 30

2 Answers2

4

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.

Franck
  • 1,754
  • 1
  • 13
  • 14
  • That seems like the correct answer, but could you please elaborate more on the "your method must be part of a component which is integrated with bean validation" part? Or point me to some reading? Thanks! – diogocarmo Sep 16 '15 at 18:25
  • Are you using BV in a JAVA EE managed environment (wildfly, websphere, GF...)? If yes then check the Java EE version your server comply to. If it is Java EE 7 then I suggest to use CDI and declare your method inside this kind of component. http://planet.jboss.org/post/bean_validation_1_1_feature_spotlight_method_validation – Franck Sep 16 '15 at 18:36
  • We're using Jersey + Grizzly in a Java 8 VM. I believe Java Bean Validation is working, so I guess the Java EE version is >= 7. I'm going to try your suggestion and use CDI (but first, understand how does that works). – diogocarmo Sep 16 '15 at 19:04
  • Grizzly is not a Java EE compliant server and it seems to be not even compliant to the Servlet specification according to this post:http://stackoverflow.com/questions/17224270/how-to-enable-cdi-inject-in-web-service-jaxrs-jersey-on-java-se-running-grizzl. – Franck Sep 16 '15 at 19:40
  • Grizzly website (https://grizzly.java.net/dependencies.html), only mentions that it's not fully compliant to Servlet specification - doesn't say anything about Java EE - where did you read that? – diogocarmo Sep 16 '15 at 19:52
  • You have 2 profiles in java ee starting from version 6. The web and full profile. The servlet api is part of the web as is cdi and bv. At this point I suggest to try and see if it works. – Franck Sep 16 '15 at 21:19
1

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.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • That sounds about right, previously I had success validating the incoming DTO. But our issue was: repeated constraints on both DTO and (the generated) Entity objects. Any idea how to work around this? – diogocarmo Sep 17 '15 at 01:39
  • I have a _theory_ to make it so that you don't have to repeat the same explicit validation code you have above, but I don't have time to implement and test it right now. Maybe a little bit later I'll post my findings if it works out. – Paul Samsotha Sep 17 '15 at 01:45
  • Great! I'm looking forward to it. – diogocarmo Sep 17 '15 at 01:47
  • Take a look at the update, and the GitHub project :-) – Paul Samsotha Sep 17 '15 at 07:53
  • Wow that was amazing! I'm still going through your code to understand what you did, but I have a question: what's the advantage of using @Valid instead of doing a 'manual' validation as I was doing? Thank you for your help! – diogocarmo Sep 17 '15 at 13:37
  • The advantage is not duplicating code. If you just have one method, sure its fine, but if you have a hundred methods, that's a lot of duplication. The `@Valid` is just a marker so the interceptor knows that it should intercept and perform your validation code. So in the interceptor, you only have the validation code in one place. The interceptor intercepts the method call and validates – Paul Samsotha Sep 17 '15 at 13:40
  • I just updated the whole project. You may want to use the new one instead. I completely removed the `@Validated` annotation. It was unnecessary. I just changed the implementation to look for the `@Valid` annotation in the method parameter instead of `@Validated` on the method. – Paul Samsotha Sep 17 '15 at 14:33