views:

122

answers:

4

I write a little web API which should it make easy to create URIs. Each resource class should contain a method createURI which takes the needed parameters. This method should use a helper method, populateUriTemplate, in the background to create an URI string. populateUriTemplate needs key value pairs to populate an URI template. In another language like Scala or Python I would use named parameters, but Java doesn't support them. So the question is: How to simulate named parameters in Java?

The straight forward solution would be to create a map:

public String createUri(int id, String name){
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("id", id);
    params.put("name", name);
    return populateUriTemplate(params);
}

But I don't like to create a map first and put each parameter to it.

Another idea is to use a static method, param, to create key value pairs:

public String createUri(int id, String name){
    return populateUriTemplate(param("id", id), param("name", name));
}

Looks much better to me!

It could be refined a bit to make it more self-explanatory, even if a few more characters are needed:

public String createUri(int id, String name){
    return populateUriTemplate(key("id").value(id), key("name").value(name));
}

I've also thought of the builder pattern, but this would force the user of my API to create an explicit builder for each resource class, what would be tedious without a benefit. The type of the parameter is not important, as long as a proper implemented toString method exists.

My favourite is one of the both approaches with the static methods above (param(key, value) or key(k).value(v)). Do you know a better way to simulate named parameters in this case?

+1  A: 

Maybe you like this approach:

class Params {
    private HashMap<String, Object> allParams = new HashMap<String,Object>();

    public Params(ParamEntry...params) {
        for( ParamEntry p : params ) {
            allParams.put(p.name, p.value);
        }
    }

    public getParam(String name) {
           return allParams.get(name);
    }

    class ParamEntry {
        public String name;
        public Object value;
    }
}

public String createUri(Params.ParamsEntry ... params){
    return populateUriTemplate(new Params(params));
}

To call it use

createUri(new Param.ParamEntry("name", valueObject) );

Inside the populateUriTemplate... just use params.get("name");

InsertNickHere
You may add a static method to create a param so it would be the same as the second idea proposed in the question.
Chris
A: 

Spring MVC does exactly this. As well as being able to bind requests to specific methods in controller classes, you can bind request parameters to method parameters. You can have a look to see how it works, but basically it picks a strategy to map the right request parameter to the right method parameter.

You basically get something like:

public String createUri(@RequestParam int id, @RequestParam String name){
    return populateUriTemplate(id, name);
}
GaryF
+1  A: 

For some ideas on the builder pattern, you could see this blog post by Stephan Schmidt.

You also just gave me the idea to do the following, with fluent interfaces, a Callable, and a static method:

createUri().id(5).name("dennetik").call();

Which would require createing a Callable class (CreateUri) with the static method:

public static final CreateUriFluentInterface createUri() {
    return FluentInterface.of(new CreateUri(), CreateUriFluentInterface.class);
}

And a fluent interface, like this:

public interface CreateUriFluentInterface {
    public CreateUriFluentInterface id(Integer id);
    public CreateUriFluentInterface name(String name);
}

Which isn't that much boilerplate code, is it?

(Well, if you tone down that horribly named CreateUriFluentInterface a bit, it isn't.)

(You would probably have CreateUriFluentInterface extend Callable<String>, to be able to reroute the call to Callable#call())

Pepijn
Cool, I can do partially parametrized functions this way! ^^
Pepijn
Looks nice, but the user of my API has to create a FluentInterface for each resource class, what I want to avoid.
deamon
A: 
populateUriTemplate("id",id, "name",name);

void populateUriTemplate(Object... nvs){
    for(int i=0; i<nvs.length/2; i++)
        ....
}
irreputable