Can we implement method overloading in web service class? - java

I would like to implement method overloading in the Java web service class as follows:
public String myMethod(User user)
{
// My code
}
public String myMethod(User[] user)
{
for(int i=0; i<user.length; i++)
{
myMethod(user[i]);
}
}
If I forward a single User object to myMethod(), it should trigger the first method and if I send an array of Users, it should trigger the second method.
In the WSDL file it shows only a single method. However, if I try to call #WebMethod(operationName="") for both calls, I am unable to generate the WSDL file.

Operation overloading is not allowed for web services.
It is explicitely prohibited in WS-BP and WSDL 1.2 also disallows it.
Even if you found a stack that has some support for this I would recommend not to follow this approach.
Overloading is an OO concept. Don't try to apply them to Service Oriented paradigm

Overloading the web service methods is not difficult. With Axis 1.4 at least it is fairly simple. If there are two overloaded methods in the service like below:
public String myMethod(String firstName, String lastName) throws RemoteException
public String myMethod(String name) throws RemoteException
Then a request like this:
http://localhost:8080/services/testService?method=myMethod&name=<name>
will invoke the second method.
And a request like this one:
http://localhost:8080//services/testService?method=myMethod&firstName=<first_name>&lastName=<last_name>
will invoke the first method.
The resolution is done by Axis.

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.

Designing Services with different types of parameters java

I am working on designing a common Service interface for atleast 5 concrete implementations. Now all these services require different types of inputs. I thought of creating a Param class to hold parameters, so that interface could remain common. but then, for some implementations, some of the fields will be unused. I also thought of using Map to hold my params, but that is also not good(casts and if-elses everywhere). Also, I thought of doing was to create a class with Static methods Service.responseAsPerFirstImplementation(p1, t1, i1) and such. But, this way is not good coding. Please suggest how I should design between Modular design, flexibility vs variability of parameters?
EDIT:
Is below the good way of doing it?
public class Client {
public static void main(String[] args) {
System.out.println(Services.response(new UserParam(1, new Date())));
System.out.println(Services.response(new PatternParam("core")));
}
}
I think the core of the question is if your parameters come from some "generic", unstructured sourcelike HTTP request parameters or command line arguments or some structured source - I would put a Swing form there as you know in advance which UI elements you have.
In case of "generic" parameters you have to convert these parameters into something your services can process. You can do this manually or with some library/framework. For instance, you can use annotations to describe how your HTTP request and its parameters map to your controllers/services/methods:
#RestController
#RequestMapping("/trainRun")
public class TrainRunController {
#RequestMapping(value = "/{year}/{month}/{day}/{trainNumber}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public TrainRun getTrainRun(#PathVariable Integer year, #PathVariable Integer month, #PathVariable Integer day,
#PathVariable String trainNumber) { ... }
}
Similarly with command-line parameters - you can use somethings like args4j to map CLI parameters into Java object first and then call your services appropriately.
Hope this helps.

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.

Conditional generation of method bodies to satisfy large interfaces in Java

The Java OpenGL GL interface contains about 2000 methods, for debugging purposes I would like to wrap an instance and delegate calls to it while doing some logging. The logging code can be pushed to the same method in each case, so the task of writing out the method implementations looks like it could be automated. An example of what I am trying to do:
import javax.media.opengl.GL;
public class GLErrorLogger implements GL {
private final GL backing;
public GLErrorLogger(GL delegateToMe) {
backing = delegateToMe;
}
private void checkErrorCode() {
// Log frame and thread details depending on gl state
}
/**
* Example of a method
*/
#Override
public int glGenLists(int arg0) {
checkErrorCode();
int retVal = backing.glGenLists(arg0);
checkErrorCode();
return retVal;
}
// rest of methods here...
}
In other words copy the method name and parameters (minus their types) into a call on the backing object, surround with calls to the logging method, and if there is a return type then assign the result to a variable of this type and return it at the end of the method.
I looked at creating a one shot eclipse code template to autogenerate the methods, but there wasn't an immediately obvious way to do pattern matching on the return type. Can anyone suggest a way to do this in Eclipse or any of its code generation tools to save me pulling out the regex toolkit?
You might want to use an Aspect to create the necessary bytecode for you instead of producing all the source code. Take a look at the Traceing Aspect example here: Traceing Aspect Example.
As an Alternative, you can create a Java Dynamic Proxy, if you do not want to use AspectJ as Thrid party Library. Please refer to Dynamic Proxy Tutorial
Use JDK proxies as suggested, or: use a Mock Framework like EasyMock or Mockito.
GL mock = EasyMock.createMock(GL.class);
EasyMock.expect(mock.someMethod()).andReturn(someValue);
// or, if you need to do more computing:
EasyMock.expect(mock.someOtherMethod()).andAnswer(new IAnswer<String>() {
public String answer() throws Throwable {
return "some value you calculate here";
}
});
EasyMock.replay(mock);
now you can use the mock Object for all methods you configured.
See the EasyMock readme for more info.

Categories

Resources