0

Here is my class:

@Stateless
@Transactional
public class PostService {
    @Inject private PostRepository postRepo;
    @Inject private UserRepository userRepo;
    @Inject private SectionRepository sectionRepo;
    @Inject private LoggedInUser loggedInUser;

    public PostDto getPost(@PostExists int id){
        Post p = postRepo.findById(id);
        //create post DTO from p
        return post;
    }

    public void delete(@PostExists int id){
        postRepo.remove(postRepo.findById(id));
    }

    public int newPost(@NotBlank @Max(255) String title,
                       @Max(2000) String body,
                       @SectionExists String sectionName){
        User user = userRepo.getByName(loggedInUser.getUsername());
        Section section = sectionRepo.getByName(sectionName);

        Post post = new Post();
        post.setTitle(title);
        post.setContent(body == null || body.isBlank() ? "" : body);
        post.setAuthor(user);
        post.setSection(section);
        post.setType(TEXT);

        return postRepo.insert(post).getId();
    }

} 

Its annotations (@NotBlank, @Max(255), etc.) are processed by a CDI interceptor (to be precise, BValInterceptor) which throws a unchecked exception if there are violated constraints.

I know that Interceptors are supposed to cover cross-cutting concerns, but this one tightly couples with my business logic since I wanted to apply design by contract methodology for my methods.

With the current setup PostService can't be instantiated using new as its interceptor wouldn't work and it wouldn't check for parameters correctness. This is fine for me since I'm never supposed to manually instantiate my service classes, but is it a good idea to write a JavaDoc for my bean with the assumption that it will always be instantiated through CDI (and so its interceptor will always be executed)?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
cidra
  • 374
  • 1
  • 4
  • 16
  • 2
    What I do is always use constructor injection. This immediately communicates the fact that this class needs several collaborators to be instantiated. Now, CDI can use package private and/or protected constructors. You can protect your constructor to communicate the intent that this class is not to be instantiated by `new`, thus needs to be instantiated by a framework. Alternatively and still with constructor injection, the constructor is annotated with `@Inject`, again hinting that this class must be instantiated by a framework. – Nikos Paraskevopoulos Jan 21 '22 at 18:14
  • 1
    @NikosParaskevopoulos i thought CDI required a zero-arg public constructor... I'll definitely try out the protected constructor methodology, looks like the best solution – cidra Jan 21 '22 at 19:07

0 Answers0