最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jakarta ee - Sub resources constraints validation - Stack Overflow

programmeradmin3浏览0评论

What is the best way to validate constraints of a Jakarta REST sub resource?

The example is as simple as possible. It's a REST web application (Jakarta 9) containing only two resources and running in a Tomee 9.1.3 container.

package fr.laboiteadodo.trysub;

import jakarta.enterprise.context.RequestScoped;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;

/**
 * Root resource
 */
@RequestScoped
@Path("samples")
public class SamplesResource {
    @Path("{code}")
    public SampleResource getSample(@PathParam("code") String code) {
        return new SampleResource(code);
    }

    // This method is validated
    @POST
    @Produces(MediaType.TEXT_PLAIN)
    public String create(@FormParam("code") @NotNull String code) {
        return code;
    }
}
package fr.laboiteadodo.trysub;

import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.*;

/**
 * Sub resource
 */
public class SampleResource {
    private String code;

    public SampleResource(String code) {
        this.code = code;
    }

    @GET
    public String getSample() {
        return code;
    }

    // This method is not validated
    @POST
    public String update(@FormParam("code") @NotNull String code) {
        this.code = code;
        return code;
    }
}

The sub resource needs to be manualy instanciated because it cannot be managed (it declares a constructor with one parameter).

The SamplesResource.create(String) method throws a ValidationException if the request does not contain a parameter named code.

The probleme is SampleResource.update(String) method does not throw anything.

What is the best way to validate constraints of a Jakarta REST sub resource?

The example is as simple as possible. It's a REST web application (Jakarta 9) containing only two resources and running in a Tomee 9.1.3 container.

package fr.laboiteadodo.trysub;

import jakarta.enterprise.context.RequestScoped;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;

/**
 * Root resource
 */
@RequestScoped
@Path("samples")
public class SamplesResource {
    @Path("{code}")
    public SampleResource getSample(@PathParam("code") String code) {
        return new SampleResource(code);
    }

    // This method is validated
    @POST
    @Produces(MediaType.TEXT_PLAIN)
    public String create(@FormParam("code") @NotNull String code) {
        return code;
    }
}
package fr.laboiteadodo.trysub;

import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.*;

/**
 * Sub resource
 */
public class SampleResource {
    private String code;

    public SampleResource(String code) {
        this.code = code;
    }

    @GET
    public String getSample() {
        return code;
    }

    // This method is not validated
    @POST
    public String update(@FormParam("code") @NotNull String code) {
        this.code = code;
        return code;
    }
}

The sub resource needs to be manualy instanciated because it cannot be managed (it declares a constructor with one parameter).

The SamplesResource.create(String) method throws a ValidationException if the request does not contain a parameter named code.

The probleme is SampleResource.update(String) method does not throw anything.

Share Improve this question edited Jan 20 at 10:58 DarkBee 15.7k8 gold badges70 silver badges114 bronze badges asked Jan 20 at 10:57 CalcimiciumCalcimicium 1151 silver badge15 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

The problem is as you stated:

The sub resource needs to be manualy instanciated because it cannot be managed (it declares a constructor with one parameter).

It is not managed, therefore @FormParam("code") ... on its method does not take effect. I can think of three ways to circumvent this limitation - but only circumvent:

  1. Reconsider if you actually need a subresource. Is it so crucial for you/your design to pass the request-specific code to the constructor of the resource? In the example it is not necessary, i.e. the subresource could be written as:

    @Path("samples/{code}")
    @POST
    public String update(
      @PathParam("code") codeFromPath,
      @FormParam("code") @NotNull String code) ...
    
  2. Do manual validation using the Bean Validation framework. This doesn't make sense for a simple string (the @FormParam("code") @NotNull String code), but it does make sens if you have a more complex object. You can inject the jakarta.validation.Validator to the parent resource, pass it to the subresource and use it from there:

    validator.validate(moreComplexObject);
    

    You probably still need to do the not-null validation by hand.

  3. Keep the web layer thin and delegate all business logic to a service layer (validation is business logic). This is similar to (2) in that you will need to inject the service in the parent resource (SamplesResource) and pass it manually to the child resource. But you don't have to deal with low-level stuff like the validator; you just make sure that the service method contains the right validation annotations:

    @ApplicationScoped
    public class SampleServiceImpl implements SampleService {
      public String update(@NotNull String code) ...
    

    ...and just pass the raw @FormParam("code") code:

    @POST
    public String update(@FormParam("code") String code) {
      return service.update(code);
      // -OR- (to be closer to the question:
      this.code = service.update(code);
      return code;
    }
    

I feel that (3) is the cleaner and more generic approach.

发布评论

评论列表(0)

  1. 暂无评论