0

I have gone through couple of tutorials, where I could see that an Interface which JAX-RS annotation is created. And later an implementation of the same is done.

Why is so? Can't I expose a concrete class directly as a RESTful Service? Is that a bad practice? Below is one of the samples which I came across in this question.

public interface ICRUD {

    @POST
    @Consumes("application/json")
    @Produces("application/json")
    @Path("create")
    public String createREST(String transferObject);

    @GET
    @Consumes("application/json")
    @Produces("application/json")
    @Path("retreive/{id}")
    public String retreiveREST(@PathParam("id") String id);

    @POST
    @Consumes("application/json")
    @Produces("application/json")
    @Path("update")
    public void updateREST(@Suspended final AsyncResponse asyncResponse, 
                          final String transferObject) ;

    @DELETE
    @Consumes("application/json")
    @Produces("application/json")
    @Path("delete/{id}")
    public String deleteREST(@PathParam("id") String id); 
}
Community
  • 1
  • 1
Sam
  • 2,352
  • 4
  • 32
  • 45

2 Answers2

3

Can't I expose a concrete class directly as a RESTful Service?

You definitely can. Have you tried it? It should work just fine.

Is that a bad practice?

Personally (and this is just my preference), I think it's bad practice to use interfaces. Some people may argue that it cleans up your code, but there are problems that come with using interfaces, for instance annotation inheritance can sometimes cause a problem for those who don't understand what the problem is. It can be really hard to spot.

If your argument is that interfaces make code cleaner, I have a couple arguments.

(1) Your code is less understandable. You need to keep referring back to the interface to see what arguments are for (e.g. inspecting the method parameter annotations). It's easier when all the annotations are in the code your actually writing.

(2) Interfaces have no implementation, so you would still need to implement every class. I personally go with an abstract base class that will implement all the basic operations. For example

public abstract class AbstractResource<T extends BaseEntity> {

    private final Repository<T> repository;

    public AbstractResource(Repository<T> repository) {
        this.repository = repository;
    }

    @GET
    public List<T> getAll() {
        return this.repository.findAll();
    }

    @GET
    @Path("{id}")
    public T getOne(@PathParam("id") long id) {
        T result = this.repository.findOne(id);
        if (result == null) {
             throw new NotFoundException();
        }
        return result;
    }

    @POST
    public Response create(T entity, @Context UriInfo uriInfo) {
        T saved = this.repository.save(entity);
        // BaseEntity should have an id property
        long id = saved.getId();
        URI createdUri = uriInfo.getAbsoluteUriBuilder()
            .path(id).build();
        return Response.created(createdUri).build();
    }
}

You could do the same for @PUT and @DELET. The core functionality is the same for all resource collections. The only thing that would need to change is the Repository type. All your implementations could just extend it like

@Path("pets")
public class PetsResource extends AbstractResource<Pet> {

    @Inject
    public PetsResource(PetsRepository repository) {
         super(repository);
    }
}

This is much cleaner. You don't need to implement the same basic CRUD operations for your concrete resources. If you want to provide other resource methods in your concrete resource class, you can do so.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
1

To say in short - the interface is not mandatory. You can expose a class as a service.

Here's a great discussion about this https://softwareengineering.stackexchange.com/questions/150045/what-is-the-point-of-having-every-service-class-have-an-interface

Kirill
  • 131
  • 1
  • 13
  • I did look at the post and could not understand Donal Fellows's answer though. Will you be able to put some light on it? It said intercations with frameworks like Spring will be simpler. How? – Sam May 09 '17 at 04:38
  • 2
    From my expirence of working with OSGI I would say, thay there's a common situation when the service implementations are loaded and executed from the other machine/environment/classloader. The separation of service and implementation alowed me to import the API interfaces and "do not care" about the implementations which were coded by other team. The changes were made in the implementation code didn't affect my code so this was the way to reduce coupling – Kirill May 10 '17 at 06:38