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()
Related
tl;dr: I'm overriding a method annotation of an interface on a child-child class, but the annotation's value is not being override.
I'm surprised I didn't found the answer for this question on this or any other site, so I think it must be something wrong with my implementation, but I can't figure it out.
I have the following custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Inherited //This only applies to class annotations, but I tried it anyway
public #interface MyRolesAllowed {
String[] value();
}
And it's used on this interface:
#Produces(MediaType.APPLICATION_JSON)
public interface IRESTfulCRUDResource<T> {
#GET
#Path("/")
#MyRolesAllowed("ADMIN")
public Response ws(#Context UriInfo uriInfo);
}
That's implemented as:
#Stateless
#Produces(MediaType.APPLICATION_JSON)
public abstract class BaseCRUDResource<T> implements IRESTfulCRUDResource<T> {
#Override
public Response wsQuery(#Context UriInfo uriInfo) {
//...
}
}
That I just override in this class to change the default annotation:
#Stateless
#Path("/something")
public class SomeResource extends BaseCRUDResource<Someclass> {
#Override
#MyRolesAllowed({"ADMIN", "USER"})
public Response wsQuery(#Context UriInfo uriInfo) {
return super.wsQuery(uriInfo);
}
}
This is all hosted on a Wildfly server, and I'm using the following interceptor to process the annotation:
#Provider
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationInterceptor implements ContainerRequestFilter {
public void filter(ContainerRequestContext requestContext) throws IOException {
Method resourceMethod = resourceInfo.getResourceMethod();
// I checked and at this point:
// resourceInfo.getResourceClass().getSimpleName() == "SomeResource"
String[] roles = resourceMethod.getAnnotation(MyRolesAllowed.class).value();
// Now, I checked and at this point:
// roles = {"ADMIN"}
// In my understanding, it should be {"ADMIN", "USER"},
// because I'm overriding the annotation on the child
// class, and resourceMethod points to the child method.
// What's wrong?
}
}
So, as stated on the last comment, I was expecting the parent's annotation to be override by the child's one, but it's not happening. This question is an example of annotation's value override.
I tried to use resourceMethod.getAnnotationsByType as well, but it provides the same values.
Am I misunderstanding something?
Update: as #JohnBollinger pointed in the comments section, I checked and resourceMethod.getDeclaringClass() == IRESTfulCRUDResource, so it's counterintuitive but ResourceInfo's getResourceMethod points to the parent method but getResourceClass points to the child class.
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
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.
I am facing issues in mocking the data for the methods which are being called without the reference e.g getMethod(); don't know how will mocking framework know about it. Below is the code for which am facing issue am not able to set HttpRequest and URIInfo in my code.
Is it possible to bypass the method.
Class A {
private HttpServletRequest httpRequest;
private UriInfo uriInfo;
public HttpServletRequest getReq() {
return httpRequest;
}
public void setReq(HttpServletRequest req) {
this.httpRequest = req;
}
public UriInfo getUriInfo() {
return uriInfo;
}
public void setUriInfo(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}}
class B extends A {
// some code
}
class C extends B {
protected Object executeCall(Object beIn) throws Exception{
prepareUpdateConfigurationRequest();
// some other methods.
return "";
}
private void prepareUpdateConfigurationRequest() {
implPutCustomerProductOrderIdProductConfigurationsImpl.setReq(getReq());
implPutCustomerProductOrderIdProductConfigurationsImpl.setUriInfo(getUriInfo());
}}
// Test class using Mockito Framework
#RunWith(MockitoJUnitRunner.class)
public class CTest {
#Mock
private A a = Mockito.mock(A.class);
#InjectMocks
private C c = new C();
private ImplBackEndInput implBackEndInput;
#Test
public void testExecuteCallObject() {
implBackEndInput = new ImplBackEndInput();
UriInfo uriInfo = Mockito.mock(UriInfo.class);
Mockito.when(a.getUriInfo()).thenReturn(uriInfo);
Mockito.when(a.getReq()).thenReturn(httpServletRequest);
try {
c.executeCall(implBackEndInput);
} catch (Exception e) {
}
}
}
Protected or privates methods cannot be mocked using Mockito, I would suggest if you are using spring to you create a DummyC class in your test package, reference that as a parent in the springConfig and make it just return the object when is called. In that way the class will use that method as a by-pass to the real class that you don't need to test.
I'm not really sure how your code is compiling, given some static references to non-static methods - A.getUriInfo() - and various other errors. It also doesn't make a whole lot of sense that you're calling setters using getters for the same object:
implPutCustomerProductOrderIdProductConfigurationsImpl.setReq(getReq());
implPutCustomerProductOrderIdProductConfigurationsImpl.setUriInfo(getUriInfo());
But to answer your question for anyone else who might wind up here, you don't need to be mocking type A in the test class at all (here):
Mockito.when(A.getUriInfo()).thenReturn(uriInfo);
Mockito.when(A.getReq()).thenReturn(httpServletRequest);
You really don't need those two lines at all. In fact, you can remove the mock of A entirely (this line): #Mock private A a = Mockito.mock(A.class);
Instead, just do:
c.setUriInfo(uriInfo);
c.setReq(httpServletRequest);
This works because C extends A, meaning all of A's methods, when not overridden, are inherited by C. So if you call the non-overridden setter methods on the instance of C, it will go straight to the methods of A. After calling the set methods shown above, when you call c.getUriInfo(), it will return the object you passed in as a parameter to the setUriInfo(uriInfo); method. No need to mock at all here.
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 :/