How can I get root-context url with JAX-RS? - jax-rs

With given Application
#ApplicationPath("/api")
public class MyApplication {
}
UriInfo#getBaseUri gives me an application path.
#Context
private UriInfo uriInfo
uriInfo.getBaseUri(); // http://address/<context-path>/api
How can I get context-path?
How can I get full URL to context-path?
http://address/<context-path>
UPDATE
I currently using code from this answer.
#Context
private HttpServletRequest servletRequest;
final URI contextUri
= URI.create(servletRequest.getRequestURL().toString())
.resolve(servletRequest.getContextPath());
Any other suggestions?

To get application context, you can inject the ServletContext in your REST method and retrieve contextPath from it, for example like this:
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Catalog find(#PathParam("id") Long id, #Context ServletContext servletContext) {
String contextPath = servletContext.getContextPath();
...
}
EDIT
To get the "full URL to context-path" you want. You could also inject the HttpServletRequest with #Context annotation and use getScheme(), getServerName() and getServerPort() methods to build it.

One possible way is using HttpServletRequest.
#Context
private HttpServletRequest servletRequest;
final URI contextUri
= URI.create(servletRequest.getRequestURL().toString())
.resolve(servletRequest.getContextPath());

Related

How to get path template in JAX-RS ContainerRequestFilter?

From within a JAX-RS ContainerRequestFilter, I'd like to obtain the unresolved path URI of the request; i.e. something like "todos/{id}". Via requestContext.getUriInfo().getPath() I only get the path with parameters resolved, e.g. "todos/1". Is there any way for getting the path with parameters instead?
You may need to just build the template. It's not that difficult. You can get access to the resource class and method (from an injected ResourceInfo) and just use the UriBuilder methods. It has path() methods that accept Class and Method and it will build the Uri for you based on the #Path annotations of those objects. Then just get the template with UriBuilder#toTemplate() For example
public class UriTestingFilter implements ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext request) throws IOException {
UriInfo uriInfo = request.getUriInfo();
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
UriBuilder partialUriBuilder = UriBuilder.fromResource(resourceClass)
.path(resourceMethod);
String partialUri = partialUriBuilder.toTemplate();
URI baseUri = uriInfo.getBaseUri();
UriBuilder fullUriBuilder = UriBuilder.fromUri(baseUri)
.path(resourceClass)
.path(resourceMethod);
String fullUri = fullUriBuilder.toTemplate();
}
}
Using ResourceInfo doesn't really work very well with sub-resources.
It's possible to get it in Jersey from the ContainerRequestContext when using using this:
List<UriTemplate> matchedTemplates = new ArrayList<>(ctx.getMatchedTemplates());
Collections.reverse(matchedTemplates);
String path = matchedTemplates.stream()
.map(UriTemplate::getTemplate)
.filter(s -> !s.equals("/"))
.collect(joining());

how to validate header params using Bean Validation and jax-rs

I have jax-rs resources and each have a same header. what is the best way to validate that the header is present using Bean Validation. I know about #HeaderParam but I don't want to change all my methods in all resources to include the header param.
It's as simple as implementing javax.ws.rs.container.ContainerRequestFilter. For example:
#Provider
public class ContentTypeValidatorFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext reqContext) {
String contentType = getHeader(reqContext, "Content-Type");
// Content-type validation, but you can valid as many headers as you want.
if (Objects.isNull(contentType)) {
throw new InvalidRequestException("Content-Type header is missing");
}
}
private String getHeader(ContainerRequestContext requestContext, String header) {
return requestContext.getHeaders().getFirst(header);
}
}
Later, to handle this exception gracefully just implement ExceptionMapper for this InvalidRequestException.
The above filter will be applied globally. But if you want to exclude some endpoints, then make use of #NameBinding to annotate your custom annotation and apply it only to specific endpoints.

ContainerRequestContext not being injected into business logic

I am using jaxrs 2.0 & am trying to populate an object in the ContainerRequestContext & retrive it in the business logic.
I am populating the object in the ContainerRequestContext like :
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MyObject myObject = new MyObject();
requestContext.setProperty("myObject", myObject);
}
And I am trying to read it in the business logic like :
#GET
#Path("/custom")
public String data(#Context ContainerRequestContext crc) {
Object pco = crc.getProperty("myObject");
}
I am using this approach from the example shared in : How to inject an object into jersey request context?
However I am getting the ContainerRequestContext crc as null. Can someone tell me what I could be doing wrong ?
I have tested the exact code asked in the question which works as it is with following setup:
spring-boot-starter-parent: 2.3.4.RELEASE
spring-boot-starter: inherited from parent
spring-boot-starter-jersey: inherited from parent
which evaluates to Spring 5.2.9.RELEASE, Jersey 2.30.1
Arquillian with Jersey can work.

How to specify HttpWebRequest.Headers["Range"] in a PCL?

I'm writing a progressive downloader as a Portable Class Library (Profile=24). It will support partial downloads of target files in chunks of bytes. HttpClient not being available, I'm going with HttpWebRequest, which has the AddRange method for partial downloads. But the method doesn't seem to be available from inside the PCL. So I set HttpWebRequest.Headers["Range"], but doing so throws the following ArgumentException:
"The 'Range' header must be modified using the appropriate property or method.\r\nParameter name: name"
That "appropriate property" seems to be HttpWebRequest.AddRange, but as I said it doesn't seem to be exposed from inside PCL. So I'm quite confused: what would be the right way of specifying the HttpWebRequest.Headers["Range"] in a PCL?
Thanks,
Simon
I didn't find the answer, but the following interface workaround worked for me:
Instead of creating the HttpWebRequest in my portable code, I defined the following custom interfaces:
public interface IMyRequest {
[...]
void AddRange(long from, long to);
}
public interface IMyRequestFactory {
IMyRequest Create(string url);
}
Then, in my non-portable code, I created classes that implemented those interfaces:
public class MyRequestImp : IMyRequest {
private readonly HttpWebRequest request;
public MyRequestImp (string url) {
request = (HttpWebRequest)WebRequest.Create(url);
}
[...]
public void AddRange(long from, long to) {
request.AddRange(from, to);
}
}
public class MyRequestFactoryImp: IMyRequestFactory {
public IMyRequest Create(string url) {
return new MyRequestImp(url);
}
}
At some point at initialization time, my non-portable code is passing a MyRequestFactoryImp object to my portable library through the IMyRequestFactory interface. Since the HttpWebRequest was created outside the PCL, you have access to the full functionalities of the class.

How can I get the whole sub path with JAX-RS?

With following URL.
http://doma.in/context/resource/some/.../undefined
I want to get the path name after ../resource which is /some/.../undefined
#Path("/resource")
class Response Resource {
final String path; // "/some/.../undefined"
}
Thanks.
UPDATE
There is, as answered, a way to do this.
#Path("/resource")
class class Resource {
#Path("/{paths: .+}")
public String readPaths() {
final String paths
= uriInfo.getPathParameters().getFirst("paths");
}
#Context
private UriInfo uriInfo;
}
When I invoke
http://.../context/resource/paths/a/b/c
I get
a/b/c
.
You can get all the URI information from UriInfo, which you can inject either as a field or method parameter, using the #Context annotation.
public Response getResponse(#Context UriInfo uriInfo) {
}
-- OR --
#Context
private UriInfo uriInfo;
You can get the absolute request path with UriInfo.getAbsoultePath()
http://doma.in/context/resource/some/somthingelse/undefined
You can get the relative path to the base uri from UriInfo.getPath().
/resource/some/somthingelse/undefined
You can get a list of path segments (each section between slashes is a path segment) with UriInfo.getPathSegments(). Here is an example usage.
There's a bunch of methods you can use for reading the URI. Just look at the API linked above.