4

I'm trying to create a simple REST service with JAX-RS (Jersey), without using Spring. I want to have the typical structure of: Resource, that use a Service (typical interface with method findById, findAll...), and that Service injected in the Resource.

It seems that CDI automatically scans beans and injects them (having a empty beans.xml in the project) but... it doesn't work for me.

This is my Resource class:

@Path("users")
@ManagedBean
public class UserController {

    @Inject
    private UserService userService;

    @GET()
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public User getUserById(@PathParam("id") Long id) {

        return userService.findById(id);
    }
}

And this is my Service and its impl class (it´s a mock...):

public interface UserService {

    User findById(Long id);

    List<User> findAll();

    User save(User user);

    User update(User user);

    void delete(Long id);
}

public class UserServiceMock implements UserService {

    // omitted constants

    @Override
    public User findById(Long id) {
        return new User()
                .setId(id)
                .setName(NAME_GANDALF)
                .setPhone(PHONE_666554433)
                .setType(TYPE_1)
                .setBirthDate(LocalDate.parse(STRING_DATE_19110102));
    }

    @Override
    public List<User> findAll() {
        return Arrays.asList(
                new User()
                        .setId(USER_ID_12)
                        .setName(NAME_GANDALF)
                        .setPhone(PHONE_666554433)
                        .setType(TYPE_1)
                        .setBirthDate(LocalDate.parse(STRING_DATE_19110102)),
                new User()
                        .setId(USER_ID_140)
                        .setName(NAME_ARAGORN)
                        .setPhone(PHONE_661534411)
                        .setType(TYPE_1)
                        .setBirthDate(LocalDate.parse(STRING_DATE_19230716)),
                new User()
                        .setId(USER_ID_453321)
                        .setName(NAME_FRODO)
                        .setPhone(PHONE_666222211)
                        .setType(TYPE_2)
                        .setBirthDate(LocalDate.parse(STRING_DATE_19511124))
        );
    }

    @Override
    public User save(User user) {
        return user.setId(USER_ID_453321);
    }

    @Override
    public User update(User user) {
        return user;
    }

    @Override
    public void delete(Long id) {
        // delete user by id
    }
}

And I'm using a "no web.xml" configuration, with this class:

@ApplicationPath("api")
public class RestApplication extends ResourceConfig {

}


The only workaround I found is to "register" the service in the RestApplication class:

@ApplicationPath("api")
public class RestApplication extends ResourceConfig {

    public RestApplication() {
        register(UserController.class);

        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(new UserServiceMock()).to(UserService.class);
            }
        });
    }
}


Is there another solution to this problem? I'd rather not to register all my services and other stuff in this class manually... I tried with annotations like @Default, @Qualifier and more (in the service), and no one works...

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
edwise
  • 869
  • 2
  • 9
  • 18

1 Answers1

5

Tomcat is a servlet container only. It's not a full Java EE enterprise stack, nor does it contain a CDI container. Apache TomEE, on the other hand, is Tomcat with EE capabilities.

Bauke Scholtz, the infamous BalusC, wrote an excellent blog on installing CDI on Tomcat. This might help you. Otherwise, an alternative approach will be to install Apache TomEE and run your application from there. After all, it's still Tomcat anyway.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • Or ditch Tomcat and use [GlassFish](https://glassfish.java.net/) instead, which is what I did. – Ken Y-N Oct 24 '14 at 08:41
  • Thank you very much! I always use tomcat for all and I forgot that... I've just tried with glassfish and it works! :) – edwise Oct 24 '14 at 09:10
  • 1
    It works with Tomcat too; its not JEE specific, you just need a proper Servlet 3.0 compatible container to be able to deploy without having any web.xml configuration. "Works on my machine", I wouldn't say that completely switching out the server software because you can't figure it out is a proper answer to this question. Possibly the implementation of JAX-RS you were using is simply too old. – Gimby Oct 24 '14 at 09:24
  • 1
    @Gimby Servlet 3 technology won't help since the CDI Container is not a Servlet container at all. Thus, the only way Tomcat will do CDI injection is through retrieving `BeanManager` from JNDI lookup. Hence I said, to rather use a Java EE complaint container, preferably the container that has a CDI container (thus alleviating JNDI lookups). – Buhake Sindi Oct 24 '14 at 10:28