URI path parameter parsing in Java - java

One of REST apis I am consuming returning urls in this format:
/api/variables{/id}
/api/projects{/id}{?skip}
The same url pattern seems to be used in JAX-WS implementations in #Path annotation so hopefully there is already some library which can help with this task.
What is the best way to parse url formatted in this way and to populate it with parameters? I would preferably use some library or Java EE core classes, to avoid custom development.
Edit:
What I am looking to achieve:
Strnig template = "/api/projects{/id}{?skip}"; // This is provided by REST service
SomeParser sp = new SomeParser(template);
sp.setParam("id", "1a");
sp.setParam("skip", "20");
sp.getUrl(); // Expected output: /api/projects/1a/?skip=20
In the meantime I found URIs are provided in format from RFC6570
The question is: Is there ready to use library that can do that?

Using JAX-RS:
#Path("/api")
public class RestService {
#Path("/variables/{id}")
public List<Variable> getVariables(#PathParam("id") String id),
#QueryParam("skip") #DefaultValue("false") boolean skip) {
// ...
}
#Path("/projects/{id}")
public List<Project> getProjects(#PathParam("id") String id) {
// ...
}
}
Be aware the / are outside the {}.
Note: Java EE provides only the API.
You need to use some implementation.

Related

Calling a web service that accept array or list of a class in Java

I want to create a web service using C#. In web service I have a web method that accept list of a specific class:
[DataContract]
public class CompositeType
{
string stringValue = "Hello ";
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
[DataMember]
public List<Product> Products { get; set; }
}
[DataContract]
public class Product
{
[DataMember]
public int PID { get; set; }
[DataMember]
public string PName { get; set; }
}
and my web method:
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
I want to publish this service using BasicHttpBinding that Java users can call it too. Now since the Java programmer is not around me, I wanted to ask those who have the experience to do this :
1) Can Java programmers call my web method that accept List<Product>?
2)Should I change List to Array?
Thanks for you contribution
Presumably your HTTP API serializes this as JSON (or maybe XML). In either case, libraries such as Jackson can handle it just fine, and most REST clients will even handle that part automatically. Standards compliance is the rule, and so as long as your List<Product> is converted to/from a regular JSON array, everything should work smoothly.
JSON doesn't have separate list types, just the plain array, so either array or list-based serialization should be equivalent.
As a note, most APIs use either camelCase or snake_case for properties, so your property names (in JSON) would be expected to be stringValue, products, pid, and pName.
As with .Net client calling WCF using the Svcutil tool, most Java users use the asis2 library which is a webservice engine to invoke web service.
WebService is a specification that any service that implements it can be called WebService. they use SOAP message based on XML to communicate. they use WSDL to describe the service details, which is used for generating the client proxy class. The reason why WCF can be called across service boundaries by various platforms is that it is also a web service. Although there may be different data types on various platforms, as long as we specify how to represent it in XML and how to serialize it, the service can be called correctly by others platforms, By default, List is specified to be serialized using a one-dimensional array.

Strings in OSGI Enroute DTOs are 'compressed'

My current task is to build an application using OSGI Enroute (http://enroute.osgi.org/) and Angular (though we elected to use Angular2/4 instead of the bundled AngularJS).
So far so good. I have a REST Java application which is responding to various requests from the Angular front-end but I'm currently running into an issue. In order to make development easier I am serving the Angular code on port 4200 and the back-end is listening on port 8080. CORS is working so I am able to send and receive requests while building the code. This may or may not be related to the issue.
The issue is when responding with a DTO with String content in excess of 21 characters the value is getting 'compressed.' I noticed this when attempting to use the value I received (a UUID) as a key for a subsequent GET request. Checking the DTO class I have confirmed that the toString() method does indeed call a private compress method where it will take any string longer than 21 characters and return something akin to this nine...last nine which tends to make it difficult to re-obtain a UUID from ... {"uuid":"95b90155-...ee5c02200", "name":"My Object"}...
So ... given something like this:
import org.osgi.dto.DTO;
public final class MyDTO extends DTO
{
public String uuid;
public String name;
}
and a REST application like this:
#RequireBootstrapWebResource(resource="css/bootstrap.css")
#RequireWebserverExtender
#RequireConfigurerExtender
#Component(name="web", propery={"debug=true"})
public final class MyApplication implements REST
{
private boolean debug = false;
public MyDTO getMe(RESTRequest request)
{
MyDTO dto = new MyDTO();
dto.name = "My Object";
dto.uuid = UUID.randomUUID().toString();
return dto;
}
#SuppressWarnings("unused")
#Activate
void activate(ComponentContext component, BundleContext bundle,
Map<String, Object> config)
{
if ("true".equals(config.get("debug"))
{
debug = true;
}
}
}
what am I missing in order to avoid this value 'compression' in my JSON responses?
Things I have tried
(The one that works) overriding the toString() method provided by DTO. This works but doesn't seem like it is the best solution. I would then have to override the toString() for anything that might have a string value in excess of 21 characters. The documentation indicates that the intent is for debugging, which likely means I'm not returning the proper type?
Setting the request's _response()'s content type to application/json: the result I see in the Chrome Web console is still a compressed string
I wrote the DTO.toString methods. It is clearly documented that the format of the output is not specified and that it is for use as a debugging tool and not for serialization. This is is why the impl "compresses" strings.
If you need to serialize a DTO, you need to use code for that purpose. See https://github.com/osgi/osgi.enroute/blob/master/osgi.enroute.base.api/src/osgi/enroute/dto/api/DTOs.java for an API that can convert DTOs to a format like JSON.

Can we have more than one #Path annotation for same REST method [duplicate]

This question already has answers here:
JAX-RS: Multiple paths
(4 answers)
Closed 2 years ago.
Can we have more than one #Path annotation for same REST method i.e. the method executed is the same, but it is executed on accessing more than one URL?
E.g.: I want to run the searchNames() method on both http://a/b/c and http://a/b.
You can't have mutliple #Path annotations on a single method. It causes a "duplicate annotation" syntax error.
However, there's a number of ways you can effectively map two paths to a method.
Regular expressions in #Path annotation
The #Path annotation in JAX-RS accepts parameters, whose values can be restricted using regular expressions.
This annotation:
#Path("a/{parameter: path1|path2}")
would enable the method to be reached by requests for both /a/path1 and /a/path2. If you need to work with subpaths, escape slashes: {a:path1\\/subPath1|path2\\/subPath2}
Serving responses with a redirection status code
Alternatively, you could set up a redirection. Here's a way to do it in Jersey (the reference implementation of JAX-RS), by defining another subresource. This is just an example, if you prefer a different way of handling redirections, feel free to use it.
#Path("basepath")
public class YourBaseResource {
//this gets injected after the class is instantiated by Jersey
#Context
UriInfo uriInfo;
#Path("a/b")
#GET
public Responce method1(){
return Response.ok("blah blah").build();
}
#Path("a/b/c")
#GET
public Response method2(){
UriBuilder addressBuilder = uriInfo.getBaseUriBuilder();
addressBuilder.path("a/b");
return Response.seeOther(addressBuilder.build()).build();
}
}
Using a servlet filter to rewrite URLs
If you're going to need such functionality often, I suggest intercepting the incoming requests using a servlet filter and rewriting the paths on the fly. This should help you keep all redirections in one place. Ideally, you could use a ready library. UrlRewriteFilter can do the trick, as long as you're fine with a BSD license (check out their google code site for details)
Another option is to handle this with a proxy set up in front of your Java app. You can set up an Apache server to offer basic caching and rewrite rules without complicating your Java code.
As explained in Tom's answer, you can not use more than one #Path annotation on a single method, because you will run into error: duplicate annotation at compile time.
I think the simplest way to get around this is to use method overloading:
#Path("{foo}")
public Response rest(#PathParam("foo") final String foo) {
return this.rest(foo, "");
}
#Path("{foo}/{bar}")
public Response rest(#PathParam("foo") final String foo,
#PathParam("bar") final String bar) {
return Response.ok(foo + " " + bar).build();
}
You could also use more different method names if you run into the case where multiple overloaded methods have the signature.
Another solution for your particular example:
http://a/b/c
http://a/b
Let's suppose that:
/a is for the resource class
/b/c and /b are the paths for the methods
because a full path looks like:
<protocol><host><port><app><url-pattern><resource-path><method-path>.
Use optional parameter
#Path("/b{c : (/c)?}")
public Response searchNames(#PathParam("c") String val) {
...
}
The example above works for all examples like:
/b
/b/
/b/c
/b/c/
but when c is provided, the val is /c (it has a / before).
If you want to fix the problem above (to avoid Java parsing), you need something more complex:
#Path("/b{slash : (/)?}{c:((?<=/).*)?}")
which will return only c (not /c) for the 3rd bullet point, but for the 4th bullet point it will return c/ which has to be parsed in Java.
But for your case ("the method executed is the same"), don't worry about parsing because you don't have different actions.
If you are using Spring then try
#RequestMapping(value = {"/def", "/abc"}, method = RequestMethod.POST)
This will work for both /abc and /def.
– sSaroj Nov 17 '17 at 10:13

Validation of method parameters

I have a RESTful web service. For implementation using JAX-RS (Jersey).
Have the following method:
public void foo (#PathParam ("name") String uuid) {
...
}
I need to do validation of input parameters. And if data invalid throw WebApplicationException.
I added my custom annotation CheckUuid (extends ):
public void foo (#PathParam ("name") #CheckUuid String uuid) {
...
}
Is it possible to do validation using annotations on a stage when the method chosen, but not yet called? For example using PreProcessInterceptor?
Java EE6 has some built in validation functionality.
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html
I have not used it however, but I saw it brought up during Java One and it looks pretty cool.
I'm not sure at what point this would happen, but I think it might work out for you.
As a result, it was decided to use the standard pattern in the method validation. Because in Jersey do not have PreProcessInterceptor.

How to return XHTML output from Apache Wink using a JSP?

I've so far been successful in setting up a basic web service using Apache Wink. This includes returning Atom, JSON, HTML, XHTML, XML, and plaintext media types, as per the samples provided. I've also been able to successfully use a MessageBodyWriter to "manually" generate the XHTML output. So far, great. I'm happy to return most of the media types via the existing Wink mechanism.
What I'm trying to do now is have the returned XHTML content use a JSP. I.e., I'd like to use a JSP as an output template, sending the POJO through as a parameter to populate the fields in the JSP. Below is some pseudocode for what I've got right now.
#Path("{id}")
#GET
#Produces({MediaType.APPLICATION_XHTML_XML})
public Response getXhtml( #PathParam("id") String id )
{
try {
MyBean mybean = service.getBean(id);
return Response.ok(new MyAsset(mybean))
.location(new URI(baseurl+"Output.jsp"))
.type(MediaType.APPLICATION_XHTML_XML).build();
} catch ( Exception e ) {
throw new WebApplicationException(e,Status.INTERNAL_SERVER_ERROR);
}
}
It just seems to ignore the JSP entirely. And if I finally do figure out how, I'll need to know how to pass the POJO as a parameter. I know there's something I'm missing here, as I assume Apache Wink can interoperate with a JSP-based web service. The Wink documentation is generally good, but I couldn't find anything on this. Thanks for any assistance, ideally a link to a working example.
There is no built-in mechanism to pass POJO as parameter. You need to build the URI yourself. Also, I guess you want to send redirect to your jsp and not just 200 OK. So you can do something like this:
#Path("{id}")
#GET
#Produces({MediaType.APPLICATION_XHTML_XML})
public Response getXhtml( #PathParam("id") String id )
{
try {
MyBean mybean = service.getBean(id);
return Response.seeOther(UriBuilder.fromUri(baseurl+"Output.jsp")
.replaceQuery(convertMyBeanToQuery(mybean)).build())
.type(MediaType.APPLICATION_XHTML_XML).build();
} catch ( Exception e ) {
throw new WebApplicationException(e,Status.INTERNAL_SERVER_ERROR);
}
}
You need to implement convertMyBeanToQuery to build a query string: key=value&key1=value
You can also use UriBuilder.queryPatam to add parameters one by one.
In the end I found a solution by playing around with some ideas gained by looking at Wink's DefectAsset example. The clue was the HtmlDescriptor class, which is found in Wink's internal API.
I'm providing my bean as the argument in an Asset's constructor (i.e., a class annotated "#Asset"), then passing the Asset through to the JSP directly as an entity in the Response:
MyBean mybean = service.getBean(id);
return Response.seeOther(new URI(baseurl+"Output.jsp"))
.entity(new MyAsset(bean))
.type(MediaType.APPLICATION_XHTML_XML).build();
This requires a method in MyAsset.java:
#Produces({MediaType.APPLICATION_XHTML_XML})
public HtmlDescriptor getHtml()
{
return new HtmlDescriptor(bean,"/Output.jsp","MyBeanPayload");
}
and in Output.jsp, I gain access to the bean via the attribute name provided as the third argument in the HtmlDescriptor's constructor:
<%
MyBean bean = (MyBean)request.getAttribute("MyBeanPayload");
String id = bean.getId();
%>
In the JSP I'm using the returned values in an HTML form so I escape them using Apache Commons Lang's StringEscapeUtils.escapeHtml() method. The returned URI doesn't include anything except the RESTful path appended with "?alt=application%2Fxhtml%2Bxml", which is used to specify the media type.
This seems to demonstrate how to pass a POJO into an output JSP via Apache Wink.

Categories

Resources