How can I get the whole sub path with JAX-RS? - 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.

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.

Spring data REST content negotiation

I have an annotated RepositoryRestResource for domain objects whose fields also contain binary data (images.) The Spring Rest machinery will create nice RESTful links for these fields, but I would also like to introduce a handler that returns the bare binary when browsers send an "image/*" accept header.
I could overlay a controller on the same paths, but it's brittle and I'd rather write a strategy class for this.
Possible? Any idea where to plug it in the Spring plumbing?
TIA,
Edoardo
Using the #RepositoryRestController annotation "properly", you should be able to restrict the controller override to the "image/*" only.
Say you have a simple domain object model (getters/setters and a some annotations omitted...)
public class Item {
#Id
private String id;
private String name;
}
Let's override the controller for image/* only
#RepositoryRestController
#ResponseBody
public class ItemRepositoryRestController {
#Autowired
private ItemRepository repository;
#RequestMapping(value = "/items/{id}", method = RequestMethod.GET,
produces = "image/*")
public Item getItem(#PathVariable(value = "id") String id)
{
Item item = repository.findOne(id);
/* do some magic with your item */
return item;
}
Obviously, no image/* data is returned here - you'll actually get a 400 error - but you do only get to this controller if asking if accepting image/*, while going through the automagic Spring Rest Controller when not asking for image/* if and only if you use #RequestMapping at the method level.
I haven't been to the point where I return raw binary data, you may have to use the HttpServletResponse directly as shown here. Or perhaps you already have an answer for this since in your comment you mention having added another resource path already (in which case I'm interested in how you return the raw data).

How can I get root-context url with 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());

RESTEasy mapping parameter with '-' in their name

A simple question (I hope so...) for RESTEasy experts.
I receive a form posted via POST which contains attributes with '-' in their names :
Example :
return-code=12
I want to map all the content of this POST into a Pojo :
public class MyFormInfo {
public String attr1="";
public String return_code=""; // don't work because return-code is not mapped in return_code
...
The method declaration is the following :
#POST
#Path("/return-cic-payment")
public String receiveForm(MyFormInfo form) throws Exception {
log.info("Return-code is : {}", form.return_code);
}
I don't to map attributes one by one in the parameters lists because the form contains a large number of fields.
Because I can't have an attribute named "return-code" in my POJO, I wonder how to do toget this parameter's value.
A custom mapping can be a solution, but I don't know how to achieve that.
Other idea I try without success, to receive a Map of attribute.
Thanks for your help.
Try this: http://docs.jboss.org/resteasy/docs/1.0.0.GA/userguide/html_single/#_Form
class MyFormInfo{
#FormParam("return-code")
private String returnCode;
//etc.
}