JAX-RS with RESTeasy Factory - java

I am trying to avoid boilerplate code in my client's requests handling through JAX-RS and RESTeasy. I have several classes, example
class User{
private String name;
private String username;
private String address;
private long id;
//getters and setters
}
class Company{
private String name;
private String address;
private String location;
//getters and setters
}
I want to have create(), update(), delete(), and getAll() responses. For example, For the User I would have the following class with a create method and subsequent update, delete and getAll:
#Path ("/user")
public class UserApi {
#PersistenceUnit
private EntityManagerFactory emf;
#POST
#Path("/create")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String Create(#Form User user){
EntityManager em = emf.createEntityManager();
try{
em.getTransaction().begin();
em.merge(user);
em.getTransaction().commit();
}
catch (Exception e){
e.printStackTrace();
em.getTransaction().rollback();
return "{\"success\":false, \"msg\":\"Error occured, please try later\"}";
}
return "{\"success\":true, \"msg\": \"Saved successfully\"}";
}
I would have to repeat the same code for each of the classes I have. Someone had commented on use of a factory class to avoid this, perhaps using generics or an Interface. I have had a hard time figuring it out. Please suggest a good design to solve this.

You must ask yourself what the differences between all implementations will be.
In this case, not much. You can copy/paste this piece of code, replace #Path("/user") with #Path("/company"), type User with Company and Bob's your uncle. Em.merge() takes any object, so we don't really care.
So because the #Path annotation is different for all, it would be acceptible to create a new Api like this;
#Path("/users")
#Stateless
public class UserApi extends AbstractCrudApi<User> {}
All elements that are unique to this REST service are defined. We have our #Path and User which is passed as a Generic Type.
Now we create this AbstractCrudApi abstract class. abstract, because we want to implement the common logic for all future services. Interfaces,as you already know, cannot have implemented methods. (Let's just forget about java 8 default methods)
#Produces(MediaType.APPLICATION_JSON)
public abstract class AbstractCrudApi<T> {
#PersistenceContext
private EntityManager em;
#POST
#Path("/create")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String create(#Form T entity) {
try {
em.getTransaction().begin();
em.merge(entity);
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
return "{\"success\":false, \"msg\":\"Error occured, please try later\"}";
}
return "{\"success\":true, \"msg\": \"Saved successfully\"}";
}
}
And that is all there is to it.
I don't quite see how a factory can be of any advantage here.
Another tip; try using the javax.ws.rs.core.Response return type instead of String. This will allow you to set a http response status as well as your response body. You can also try using Jackson to marshall your response objects. Check resteasy-jackson2-provider.

Related

Why should an Interface be declared for JAX-RS implementation?

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);
}
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.
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

jax-ws invocation in Jersy

We have Rest services implemented using Jersy,my question is when invoking some soap service from our rest implementation, we are creating object for delegate like below,
#POST
#Path("/forgotuserid/validate/mobilenumber")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ServiceResponse validateMobileNumber(CommunicationDTO commonDTO)
throws ApplicationException, Exception {
ChMTYWebservicesProvidersWsMTY service = new ChMTYWebservicesProvidersWsMTY();
WsMTYPortType portType = service.getChMTYWebservicesProvidersWsMTYPort();
//TODO : other stuffs go here
return response;
}
is there any way to avoid new object creation and have single here?
If you are using Spring framework then there is an option Dependency Injection , You can use that feature.
You can code something like this:
public class SoapWSUtil{
private static WsMTYPortType type;
static {
type = (new ChMTYWebservicesProvidersWsMTY()).getChMTYWebservicesProvidersWsMTYPort();
}
public static WsMTYPortType getType(){
return type;
}
}
And then use it as SoapWSUtil.getType(). It will be thread safe in case, if you won't add state to SoapWSUtil

Grizzly REST - POSTs are always 404

In my endpoint, I have some methods with #GET and some methods with #POST. #GETs are working fine, but #POSTs always return 404.
Here is some part from the endpoint's interface:
public interface TestEndpoint {
#GET
#Path("/ping")
Response ping();
#POST
#Path("/weather/{iata}/{pointType}")
Response updateWeather(#PathParam("iata") String iataCode,
#PathParam("pointType") String pointType,
String datapointJson);
#POST
#Path("/airport/{iata}/{lat}/{long}")
Response addAirport(#PathParam("iata") String iata,
#PathParam("lat") String latString,
#PathParam("long") String longString);
#GET
#Path("/exit")
Response exit();
}
Here is the server initialization part:
public class TestServer {
private static final String BASE_URL = "http://localhost:9090/";
public static void main(String[] args) {
try {
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(TestEndpointImpl.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URL), resourceConfig, false);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
server.shutdownNow();
}));
HttpServerProbe probe = new HttpServerProbe.Adapter() {
public void onRequestReceiveEvent(HttpServerFilter filter, Connection connection, Request request) {
System.out.println(request.getRequestURI());
}
};
server.getServerConfiguration().getMonitoringConfig().getWebServerConfig().addProbes(probe);
server.start();
Thread.currentThread().join();
server.shutdown();
} catch (IOException | InterruptedException ex) {
Logger.getLogger(TestServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
where, TestEndpointImpl is an implementation of TestEndpoint (as the name implies) with class-level annotation #Path("/collect").
When I perform GET requests, it works fine. But POSTs are problematic. Corresponding methods are not called.
As a side note, probe prints both GET and POST requests as expected, so I am sure that requests reach the server and paths are ok.
Is there any suggestion?
EDIT: Some snippet from the implementation:
#Path("/collect")
public class TestEndpointImpl implements TestEndpoint {
...
#Override
public Response updateWeather(#PathParam("iata") String iataCode, #PathParam("pointType") String pointType,
String datapointJson) {
System.out.println("TRACE: " + datapointJson);
// do something and return a Response
}
...
}
The registered probe prints /collect/weather/BOS/wind, but updateWeather is not called.
Short answer
Copy the #POST and the #Path annotations to the method implementation. It will do the trick.
Long answer
The section regarding annotation inheritance of the JAX-RS 2.0 specification (the specification which Jersey is the reference implementation) is pretty clear. See the quote below:
3.6 Annotation Inheritance
JAX-RS annotations may be used on the methods and method parameters of a super-class or an implemented interface. Such annotations are inherited by a corresponding sub-class or implementation class method provided that the method and its parameters do not have any JAX-RS annotations of their own. Annotations on a super-class take precedence over those on an implemented interface. The precedence over conflicting annotations defined in multiple implemented interfaces is implementation specific. Note that inheritance of class or interface annotations is not supported.
If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored. E.g.:
public interface ReadOnlyAtomFeed {
#GET
#Produces("application/atom+xml")
Feed getFeed();
}
#Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
public Feed getFeed() {...}
}
In the above, ActivityLog.getFeed inherits the #GET and #Produces annotations from the interface. Conversely:
#Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
#Produces("application/atom+xml")
public Feed getFeed() {...}
}
In the above, the #GET annotation on ReadOnlyAtomFeed.getFeed is not inherited by ActivityLog.getFeed and it would require its own request method designator since it redefines the #Produces annotation.
For consistency with other Java EE specifications, it is recommended to always repeat annotations instead of relying on annotation inheritance.
That can also happen if the url is not in the correct format; for example you could have sent a request without the correct path parameters.

How to reuse a REST methods in different resources?

Hi,
I am building a REST-api using Jersey and Java. I wonder if it is possible to reuse a method in many resources.
As an example If I have this code:
#Path("/users")
public class UserResource {
#GET
#Path("/{uid}/comments")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> getComments() {
return commentService.getOnEntity("User", uid);
}
}
and this:
#Path("/items")
public class ItemResource {
#GET
#Path("/{uid}/comments")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> getComments() {
return commentService.getOnEntity("Item", uid);
}
}
Is it possible to reuse the code for specifying the method "/{uid}/comments/" so I do not need to write it in every resource that is going to need it?
I guess I could extend a CommentResource with the method, but the I can only add one set of methods. If I use Interface I could specify more than one set of methods but would have to rewrite the code inside the methods in every resource.
Edit
After a tips from #thomas.mc.work I rewrote my code using a sub resource. It is better than the first solution since I get all methods from my sub resource and it only takes 4 lines of code per resource. This is how it looks like:
#Path("/users")
public class UserResource {
#Path("/{uid}/comments")
public CommentSubResource getCommentSubResource(#PathParam("uid") String uid) {
return new CommentSubResource("User", uid);
}
}
and this:
#Path("/items")
public class ItemResource {
#Path("/{uid}/comments")
public CommentSubResource getCommentSubResource(#PathParam("uid") String uid) {
return new CommentSubResource("Item", uid);
}
}
and this:
public class CommentSubResource {
private String entity;
private String entityUid;
public CommentSubResource(String entity, String entityUid) {
this.entity = entity;
this.entityUid = entityUid;
}
#GET
#Path("/")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> getComments() {
return commentService.getOnEntity(entity, entityUid);
}
#DELETE
#Path("/")
#Produces(MediaType.APPLICATION_JSON)
public List<Comment> deleteComment(#PathParam("uid") String uid) {
return commentService.delete(uid);
}
}
This is much better. I have an idea to use java 8 and default implementation interfaces to be able to just implmenet an interface to get the functionality, but I am not sure if I am able to determine which resource the default implemented method is called from.
Edit
After some laboration I think subresources is the way to go, even if it´s not (according to me) the perfect solution.
There is a similar feature called "Subresource Locators". You can decide in runtime which Resource is selected to process the request that is matching your JAX-RS method.

How to get resource object in RequestFilter in Jersey

As I understand, it's possible to get resource class and method using injected ResourceInfo, but I need to execute some method of my resource class in request filter, so I need to get this object.
Or maybe the whole idea of getting exact object is wrong in this case?
UPD:
Here is a description of the original problem:
For example I have resource that returns all users and it also can return a subresource for particular user:
#Path("users") public class UsersResource {
#GET List<User> getUsers() {...}
#Path("{id}") UserSubresource getById(PathParam("id") String id) {
return new UserSubresource(getUserById(id));
}
}
Here is UserSubresource:
public class UserSubresource {
User user;
#GET public User getUser() {return user;}
...
public boolean isAccessible() {
return user.isAccessibleByCurrentUser();
}
}
And I need to check access rights for getUser() method, I can't check permissions before I find out actual user.
I understand that I can add this check in getUser() method itself, but this situation is the same for some other entities in my application, so I want more common solution.

Categories