Skip to content

Instantly share code, notes, and snippets.

@purplefox
Created April 4, 2012 12:46
Show Gist options
  • Save purplefox/2300852 to your computer and use it in GitHub Desktop.
Save purplefox/2300852 to your computer and use it in GitHub Desktop.
It's nice being able to set properties by passing them to the constructor in Groovy:
def foo = new Foo(bar: 23, wibble: "hello")
But if Foo is created via a factory method instead:
def foo = Foo.createFoo(bar: 23, wibble: "hello")
It doesn't work
where
class Foo {
.. properties
static Foo createFoo() {
return new Foo();
}
}
How can I get this to work with factories?
@purplefox
Copy link
Author

What if Foo takes another constructor argument (used for some other purpose), is it possible to do this: ?

class Foo {

.. properties

static Foo createFoo(someOtherArg, Map properties) {
return new Foo(someOtherArg, properties);
}

}

@antoineroux
Copy link

That could work, only if you defined yourselft the constructor Foo(T someOtherArg, Map properties).

Another way would be to do the following. Let's say you want to set the properti prop1 with someOtherArg:

class Foo {

  .. properties

  static Foo createFoo(someOtherArg, Map properties) {
     return new Foo([prop1: someOther Arg] + properties)
  }

}

Is is something like that you want to do? Do you have a more specific code example?

@purplefox
Copy link
Author

Here is the real code: https://github.com/purplefox/vert.x/blob/no-singleton/src/main/groovy/org/vertx/groovy/core/Vertx.groovy

I want to be able to call the method Vertx.createHttpServer specifying some properties which should get passed through to the underlying HttpServer instance which has the props set on it.

I.e. I want to do this:

def httpServer = vertx.createHttpServer(port:80, host:"foo.com")

This used to work when HTTPServers were created directly by the user but now no longer works since a factory is used.

@purplefox
Copy link
Author

I solved this by manually applying the properties from the map in the constructor

@pledbrook
Copy link

I'm not sure what your solution is, but I thought I'd point out that if you specify the Map as the first argument, you can have proper named argument support:

static Foo createFoo(Map properties, someOtherArg) {
    return new Foo([prop1: someOther Arg] + properties)
}

Foo.createFoo(host: "localhost", port: 8080, "something")

I think that does what you want.

@purplefox
Copy link
Author

someOtherArg does not represent a property so putting it in the map of properties does not make sense to me. I also tried it and it didn't seem to work

You can see how I fixed it here https://github.com/purplefox/vert.x/blob/no-singleton/src/main/groovy/org/vertx/groovy/core/Vertx.groovy

By applying the properties manually

@pledbrook
Copy link

Ooops, sorry, I copied the wrong snippet. Whether someOtherArg is treated as a property or not is irrelevant. The key point is that the first argument should be a map:

static Foo createFoo(Map properties, someOtherArg) {
    return new Foo(someOtherArg, properties);
}

Foo.createFoo(jVertx, host: "google.com", port: 80)

Note that named arguments can appear anywhere in the argument list: they are all collated into a single map which becomes the first argument.

BTW, indent code blocks by four spaces and you'll get the code formatting in gists and their comments (it's standard Markdown).

@purplefox
Copy link
Author

@pledbrook
Copy link

I can't help but think we're talking about different things here. What doesn't work for you exactly? Sorry, I'm just not understanding what you're getting at.

@purplefox
Copy link
Author

I want to Groovy to automatically apply the properties, as you can see from the link above I'm doing it manually.

@pledbrook
Copy link

If I understand you correctly, you want Groovy to recognise the factory pattern and automatically pass the factory method arguments through to the constructor of the created instance? Not sure any language does that :) You can always manage it via AST transforms, but that seems like wasted effort.
Anyway, what you have currently is what I would do, although I would probably make the Map the first argument of the constructors rather than the second.

@purplefox
Copy link
Author

No, I don't mean that.

I know Groovy can automatically apply properties without me having to code any manual property application code if I call a no arg constructor:

I.e.

class Foo {
  Foo() {
  }
}

This allows me to construct the object like so:

def foo = new Foo(port:80, host: "localhost")

The problem is my Foo class already takes another arg in its constructor (which is not a property), i.e. Foo is really like this:

class Foo {
  Foo(someOtherParam) {
  }
}

I was hoping that Groovy would still automatically apply params in this case, i.e. allow me to do:

def foo = new Foo("wibble", [port:80, host: "localhost"])

but that doesn't seem to work.

hence.. I am applying the params manually

@pledbrook
Copy link

OK, I finally understand. You're right, you can't get automatic property binding once you're no longer using the default constructor. I've been told it may be worth a JIRA :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment