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
Related
I am writing a custom Jersey 2.0 server logging filter.
Sample: https://github.com/jersey/jersey/blob/master/core-common/src/main/java/org/glassfish/jersey/logging/ServerLoggingFilter.java
A reference to ResourceInfo is injected as:
#Context
private ResourceInfo resourceInfo;
Interface ResourceInfo has two methods:
Class<?> getResourceClass()
Method getResourceMethod()
Is there ever a case where ResourceInfo.getResourceClass() != ResourceInfo.getResourceMethod().getDeclaringClass()?
Bonus question: Both methods may return null. Is it possible that only one would be null?
Can't say much about null values, but there is a case when getResourceClass() != getResourceMethod().getDeclaringClass() if you have some class hierarchy like superclass resource. It is easier to show in code, so consider this:
public class SuperResource {
#GET
#Produces({ MediaType.APPLICATION_JSON })
public Response getInfo() {
return Response.ok("{\"info\":1}").build();
}
}
#Path("test")
public class MyResource extends SuperResource{
// ... other endpoints
}
Now lets call
GET http://localhost:9998/test/
getResourceClass() : class ru.varren.MyResource
getResourceMethod(): javax.ws.rs.core.Response ru.varren.SuperResource.getInfo()
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.
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.
This code works to access the uriInfo:
#Path("/testing")
public class Testing {
#javax.ws.rs.core.Context UriInfo uriInfo;
#POST
#Path("/test2")
#Produces(MediaType.TEXT_PLAIN)
public Response test2(
#FormParam("sessionId") String sessionId ) {
String currentUserId = Utils.setup(sessionId);
String accessPath = uriInfo.getAbsolutePath().toASCIIString();
System.out.println("The client used this URI to reach this resource method: " + uriInfo.getAbsolutePath().toASCIIString());
// Utils.test3("print this");
return Response.ok("Test 2 ended").build();
}
When I try to access the uriInfo in the called method Utils.test3("print this"); Here:
public class Utils {
#javax.ws.rs.core.Context static UriInfo uriInfo;
public static String setup(String sessionId) {
if (!com.retailapppartners.Utils.validSession(sessionId)) {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
String currentUserId = com.retailapppartners.Utils.getUserFromSession(sessionId);
MDC.put("user-id", currentUserId);
return currentUserId;
}
public static void test3(String message) {
System.out.println(message);
String path = uriInfo.getPath();
// System.out.println("The client used this URI: " + uriInfo.getAbsolutePath().toASCIIString());
return;
}
This fails with null pointer exception. I want to see the path uri in the called method to confirm security for all methods in my utils called method. I have searched hi and low for called examples of this. Thanks
Use the #Context annotation to inject an instance of UriInfo into an field variable or method parameter of your resource class
e.g. #1
public String find(#Context UriInfo uri){}
e.g. #2
public class RESTResource{
#Context
private UriInfo uri;
}
Continuing with my comment.. into an answer
Like I said, you can't just decide to inject it anywhere you want. The class being injected into needs to be managed by the JAX-RS runtime, as it's the one that will be doing the injecting. A resource class is managed, a filter provider is managed, that's why you can inject into them. You're utility class is not. And in any case, I don't think it would even work for a [static] "utility" class (even if you were to somehow get it managed) because of the static nature.
Let me just first mention, that UriInfo is specific to each request. static, by nature is "global". You cannot inject it as a static field.
One solution I can see is to make the Utils class (and methods) non-static, and use the underlying injection framework to inject an instance of the Utils class, where ever you need it. This way, if the Utils class is managed, then it should be able to inject the managed UriInfo instance. How this (getting the Utils class managed) will be achieved depends on the implementation you are using, and it's underlying injection framework.
For instance, with Jersey (2), I could do this
public class Utils {
#Context UriInfo uriInfo;
public String test(String s) {
return s + "=" +uriInfo.getAbsolutePath().toString();
}
}
#Path("some")
public class SomeResource {
#Inject
Utils utils;
#GET
public Response getSomething() {
return Response.ok(utils.test("Hello")).build();
}
}
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("stackoverflow.jersey.test");
register(new AbstractBinder(){
#Override
protected void configure() {
bind(Utils.class).to(Utils.class);
}
});
}
}
And this works just fine
C:\>curl -v http://localhost:8080/some
Result: Hello=http://localhost:8080/some
Jersey uses HK2 for its injection, so I am able to leverage it to injection of my Utils class.
Now this is probably not the answer you're looking for (as it defeats the purpose of a static utility class), but what you are trying too just can't be done. Either way you go, whether refactoring to pass the UriInfo to your static methods, or the solution above, you will probably have a lot of refactoring to do. I'm surprised you've already created 200 methods using this functionality, before making sure one worked :/
I have this question about best practices in following examples:
interface Request;
interface Service {
void process(Request request)
}
class MyService implements Service;
class YourService implements Service;
class MyRequest implements Request;
class YourRequest implements Request;
But how to ensure that MyService will always receive MyRequest and YourService will get YourRequest only, and not in the opposite way? Obvious answer "if-instance-of-check" in MyService.process(...) seems ugly and somehow against SOLID principles. Maybe there are better ways around?
Maybe generics would be good solution? (But then, how to use them in code that has to run under Java 1.4?)
Put simply, you are establishing an interface that you then don't want to adhere to, so it's not really an ideal design.
What I mean is, if MyService implements Service, then it must be able to take any kind of request. Otherwise it isn't following the defined contract.
I would question why you have the Service interface at all in this instance, and if you do need it (for other methods) whether it's appropriate for the process(Request request) method to be on there if subclasses are not going to honour it.
If the design of the contract is that each Service can process any kind of Request, then your implementation of MyService , which only takes MyRequest (and breaks if other kinds of Requests are passed in), is wrong.
If the design of the contract is that Service and Request subclasses maps to each other, e.g., MyService can (and should) only process a MyRequest, then you will need to change the interface of Service. Otherwise, the current interface as written in the question does not do what the question describes it to do. One way to fix is to parameterize the Service interface:
interface Service<R> {
void process(R request);
}
then your concrete MyService will be
public class MyService implements Service<MyRequest> {
public void process (MyRequest r) {/*blah*/}
}
You can see an example of this in action in the JDK - the Comparator interface does exactly this, for exactly the same reason. http://java.sun.com/javase/6/docs/api/java/util/Comparator.html
I cant see why you would, but if you still want to restrict the hierachy of MyRequest to be a request, then you can swap Service<R> with Service<R extends Request>
edit: this obviously doesnt run in 1.4, so to do the same thing[1] , you will need to use a visitor pattern. Its uglier, but 1.4 is ugly =)
interface Service {
void process(Request visitor);
}
interface RequestVisitor {
void visitMyRequest(MyService service);
void visitYourRequest(YourService service);
void visitTheOtherRequest(TheOtherService service);
}
interface Request extends RequestVisitor { /* and any extra methods required for request*/ }
public class MyService implements Service {
public process(Request r) {r.visitMyRequest(this);}
public void doSpecialMyProcessing(MyRequest request) { /* your code using MyRequest*/ }
}
public class YourService implements Service {
public process(Request r) {r.visitYourRequest(this);}
public void doSpecialYourProcessing(YourRequest request) { /* your code using YourRequest */ }
}
public class MyRequest implements Request {
void visitMyRequest(MyService service) {
service.doSpecialMyProcessing(this);
}
void visitYourRequest(YourService service) {
throw new UnsupportedOperation("Cannot call visitYourRequest in MyRequest!");
}
void visitTheOtherRequest(TheOtherService service) {
throw new UnsupportedOperation("Cannot call visitTheOtherRequest in MyRequest!");
}
}
public class YourRequest implements Request {
void visitMyRequest(MyService service) {
throw new UnsupportedOperation("Cannot call visitMyRequest in YourRequest !");
}
void visitYourRequest(YourService service) {
service. doSpecialYourProcessing(this);
}
void visitTheOtherRequest(TheOtherService service) {
throw new UnsupportedOperation("Cannot call visitTheOtherRequest in YourRequest !");
}
}
[1] actually its not the same, because now you will need to write a method for each request subtype. In 1.4, you would have to cast and do instanceof etc, to achieve what 1.5 can do with generics.
In my opinion generics would suit better here. Your interfaces pretend that a service can handle any type of Request. But in fact the implementations of each seem to be tightly coupled.
Anything implementing Service should expect to implements its methods as they are. If MyService and YourService require different method prototypes, then they are different interfaces.
Think of it from the other direction. Without knowing the implementation behind a Service interface, any caller should able to call Service.process(request) with any implementation of Request, and expect to receive a valid response.
try introducing another level of indirection:
interface Module {
Service createService();
Request createRequest();
}
class MyModule implements Module {
Service createService() { return new MyService(); }
Request createRequest() { return new MyRequest(); }
}
class YourModule implements Module {
Service createService() { return new YourService(); }
Request createRequest() { return new YourRequest(); }
}