简体   繁体   中英

Generics and Dependency Injection in Java

I am developing a Java EE application that uses JAX-RS for the WebLayer.

I tried to break down the problem. So the code you'll see is just a cutout. For now everything works fine. As you can see I have an UserEndpoint where a client can create a new user. After everything is done a verification mail is sent by the VerificationService .

UserEndpoint

@Path("/users")
@Stateless
public class UserEndpoint {

    @Inject
    @AuthenticatedUser
    private User authenticatedUser;

    @EJB
    private UserDAO userDAO;

    @EJB
    private TokenDAO tokenDAO;

    @Inject
    private PasswordValidator passwordValidator;

    @Inject
    private UserValidator validator;

    @Inject
    private VerificationService verificationService;

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public User createUser(User user) {

        // Validation and Creation

        // Verification
        this.verificationService.sendVerificationMail(user);

        return user;
    }
}

VerificationService

@Singleton
public class VerificationService {

    @Inject
    private MailService mailSender;

    @Inject
    private TemplateService templateService;

    public void sendVerificationMail(User user) {
        this.templateService.setUserTemplate(TemplateCategory.VerificationTemplate, user);
        mailSender.sendMail(new Message(
            MessageDAO.systemEmailAddresses.get(0),
            user.getEmail(),
            templateService.getSubject(),
            templateService.getContent()));
    }
}

Because I want to have a scalable project I decided to encapsulate parts of the endpoint, so I can make use of it in other projects. Since every user has to be verified in one way or another I thought that the encapsulation of the verification process would be a good idea. The problem is that I have no clue how to realize that. My first approach was as followed:

CoreUserEndpoint

@Path("/users")
@Stateless
public abstract class CoreUserEndpoint<D extends BaseUserDAO<T>, T extends BaseUser, V extends CoreUserValidator<D, T>> extends EntityEndpoint<D, T, V> {

    @EJB
    private TokenDAO tokenDAO;

    @Inject
    private PasswordValidator passwordValidator;

    @Inject
    private VerificationService<T> verificationService;

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public User createUser(User user) {

        // Validation and Creation

        // Verification
        this.verificationService.sendVerificationMail(user);

        return user;
    }
}

EntityEndpoint

@Stateless
public class EntityEndpoint<D extends CoreDAO<T>, T extends CoreEntity, V extends CoreValidator> {

    protected D entityDAO;

    @Inject
    @AuthenticatedUser
    protected T authenticatedUser;

    protected V entityValidator;

}

VerificationService

@Singleton
public class VerificationService<T extends BaseUser> {

    @Inject
    private MailService mailSender;

    @Inject
    private TemplateService<T> templateService;

    public void sendVerificationMail(User user) {
        this.templateService.setUserTemplate(TemplateCategory.VerificationTemplate, user);
        mailSender.sendMail(new Message(
            MessageDAO.systemEmailAddresses.get(0),
            user.getEmail(),
            templateService.getSubject(),
            templateService.getContent()));
    }
}

When I tried this I get the famous WELD-001408: Unsatisfied dependencies error. And I think I do understand why this is happening. As I read here I cannot make use of generics, neither for @Inject nor for @EJB . But if I am not able to use generics how can I encapsulate the core of my project? Is their any work around or a different approach? I am sure there already is a solution for that anywhere in the internet. But after 3 days of searching without making any progress I get really frustrated and thought It would be best to ask you guys. So I would really appreciate if you could point me in the right direction.

I'm just trying to understand the logic. Since my comments with questions are too long, I decided to post here in aswer section.

Disclaimer: It doesn't answer you question directly

So, let's start:

A generic class is defined with the following format:

class name<T1, T2, ..., Tn> { /* ... */ } The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, ..., and Tn .

1. So by doing this:

public abstract class CoreUserEndpoint<D extends BaseUserDAO<T>, T extends BaseUser, V extends CoreUserValidator<D, T>>

the type variables D extends BaseUserDAO<T>, T extends BaseUser, V extends CoreUserValidator<D, T> , instruct Java compiler that in order to use CoreUserEndpoint one needs to specify the types.

2. Next when you do this:

public abstract class CoreUserEndpoint<...> extends EntityEndpoint<D, T, V> 

you use the previously defined type arguments to be used in EntityEndpoint . Now, compiler would look for classes (or interfaces, ...) named D , T and V .

Here comes the part which I am not sure about. If compiler finds them from your declaration for CoreUserEndpoint , then you're trying to force the class to extend from multiple classes, which is not allowed, by doing this:

public class EntityEndpoint<D extends CoreDAO<T>, T extends CoreEntity, V extends CoreValidator>

PS I would higly appreciate any feedback, if what I've written here makes any sence, from experience Java devs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM