Groovy - Is it possible to pass a class as a parameter? - groovy

This is just a very basic example of what I want to do. There's a bit more that goes on in the foobar method, but it's the gist of what I'm doing. It obviously doesn't work, since it fails to compile, but I'm wondering if I'm just passing the class incorrectly or using the 'className' parameter in the wrong way. I know I can rework it to take the string of the class name and just match it, but it seems a shame to do that. This would be so nice and DRY.
class Foo {
String name
}
class Bar {
String name
}
def foobar(field, className) {
def instance = className.findByName(jsonParams.field)
if(!instance) {
instance = new className(name: jsonParams.field)
}
return instance
}
foobar(foos, Foo)
foobar(bars, Bar)
I don't know much Java or Groovy, so I'm not sure what's possible vs impossible yet. Feel free to just tell me "No." I've tried googling and haven't found anything that really answers the question for me. A simple no would be great at this point haha.

Yes, it is possible to pass class as argument - in Groovy, classes are first class citizens (see this thread for more detail).
This construct: instance = new className(name: jsonParams.field) actually tries to create an instance of class named className, not of the class referenced by this variable. To make it compile, you need to call Class.newInstance:
class Foo {
String name
}
class Bar {
String name
}
def foobar(String name,Class clazz) {
def instance = clazz.findByName(name)
if(!instance) {
instance = clazz.newInstance(name:name)
}
return instance
}
foobar('foo', Foo)
foobar('bar', Bar)
​
I'm not entirely sure what you want to achieve with the findByName method, though - neither Foo nor Bar have a static method named findByName as far as I can tell.

Related

How to instantiate classes only from inside another class in Haxe

I need to prevent class A from being instantiated anywhere but only from another class B, then class B can return the created instance of class A which can be used in any other class.
I understand that B could be a Factory in this example, I looked in the factory pattern in the Haxe code cookbook but it does not seem suit what I am looking for.
In my example class B is doing some work then should return the result in an instance of class A.
no one should be able to create an instance of class A because it is the result of the work that class B performs. anyone needs an instance of A should ask B to do the work and return the resulted A instance
hope I explained it clearly
You would usually do this by using #:allow() metadata in combination with a private constructor:
A.hx:
class A {
#:allow(B)
private function new() {}
}
B.hx:
class B {
public static function create():A {
return new A(); // compiles
}
}
Trying to instantiate A outside of B will result in a compiler error:
class Main {
static function main() {
new A(); // Cannot access private constructor of A
}
}
Note that it's still possible to work around this by using #:access() or #:privateAccess metadata - in Haxe, nothing is ever truly private. It follows a philosophy of "the programmer knows best", which can be very powerful.
Also, you might want to declare A as #:final so nothing can subclass it, because subclasses can access private fields in Haxe. But again, this can be overriden with #:hack metadata.

Groovy Copying / Combining MetaMethods From Multiple Objects

I have two classes. At runtime, I want to "clone" the methods of one object, over to another. Is this possible? My failed attempt using leftshift is shown below.
(Note: I also tried currMethod.clone() with the same result.)
class SandboxMetaMethod2 {
String speak(){
println 'bow wow'
}
}
class SandboxMetaMethod1{
void leftShift(Object sandbox2){
sandbox2.metaClass.getMethods().each{currMethod->
if(currMethod.name.contains("speak")){
this.speak()
this.metaClass."$currMethod.name" = currMethod
this.speak()
}
}
}
String speak(){
println 'woof'
}
}
class SandboxMetaMethodSpec extends Specification {
def "try this"(){
when:
def sandbox1 = new SandboxMetaMethod1()
def sandbox2 = new SandboxMetaMethod2()
sandbox1 << sandbox2
then:
true
}
}
//Output
woof
speak
woof
Per Request, I am adding background as to the goal / use case:
It's very much like a standard functional type of use case. In summary, we have a lot of methods on a class which applies to all of our client environments (50-100). We apply those to process data in a certain default order. Each of those methods may be overridden by client specific methods (if they exist with the same method name), and the idea was to use the approach above to "reconcile" the method set. Based on the client environment name, we need a way to dynamically override methods.
Note: Overriding methods on the metaclass is very standard (or should i say, it's the reason the amazing capability exists). And it works if my method exists as text like String currMethod = "{x-> x+1}", then i just say this.metaClass."$currMethodName" = currMethod. My challenge in this case is that my method is compiled and exists on another class, rather than being defined as text somewhere.
The goal of having all the custom methods compiled in client-specific classes at build time was to avoid the expense of compilation of these dynamic methods at runtime for each calculation, so all client-specific methods are compiled into a separate client-specific JAR at build time. This way also allows us to only deploy the client-specific code to the respective client, without all the other clients calculations in some master class.
I hope that makes sense.
New Approach, in Response to Jeremie B's suggestion:
Since I need to choose the trait to implement by name at runtime, will something like this work:
String clientName = "client1"
String clientSpeakTrait = "${clientName}Speak"
trait globalSpeak {
String speak() {
println 'bow wow'
}
}
trait client1Speak {
String speak() {
println 'woof'
}
}
def mySpeaker = new Object().withTraits globalSpeak, clientSpeakTrait
A basic example with Traits :
trait Speak {
String speak() {
println 'bow wow'
}
}
class MyClass {
}
def instance = new MyClass()
def extended = instance.withTraits Speak
extended.speak()
You can choose which trait to use at runtime :
def clientTrait = Speak
def sb = new Object().withTraits(clientTrait)
sb.speak()
And dynamically load the trait with a ClassLoader :
def clientTrait = this.class.classLoader.loadClass "my.package.${client}Speak"
def sb = new Object().withTraits(clientTrait)

Why does Groovy sometimes not require a return type (or even def) on methods?

I am asking "why is this possible in Groovy?" for the following two code blocks. Maybe I should have created two separate questions, but these seem closely related.
First,
class Dog
{
public speak() {
return "Bark"
}
}
Notice how speak() doesn't have a return type, and I didn't say def. Yet, the code works as if I included def.
Second,
#interface MyAnnotation {
}
interface Canine{
#MyAnnotation
speak()
}
Notice how the speak() method doesn't have a return type, but it works when I put an annotation on the method.
Why do both of these code blocks work (i.e., no errors when I use them)? Why does the first one work iff I put public before it, and why does the second one work iff I put an annotation on it? And where is this documented?
EDIT:
Here is a runnable script that demonstrates both oddities:
#interface MyAnnotation { }
interface Canine{
#MyAnnotation
speak()
}
class Dog implements Canine
{
public speak() {
return "Bark"
}
}
Dog fido = new Dog()
println fido.speak()
Groovy is designed to be flexible and permissive. As long as you use either def, a return type, public, or an annotation, and you have () at the end (and the name doesn't match the enclosing class), the interpreter figures out that it's a method declaration and it lets you do it. If you don't care about the return type enough to indicate it, Groovy is also fine with not caring about it. That's the design philosophy.
This syntax isn't documented anywhere I can find. I would guess that indicates this syntax is subject to change. I would hesitate to rely on this and would stick to using def or a return type, if only for the sake of clarity.

#Delegate class without default constructor

How can I create a delegate class in Groovy for a class which doesn't have a default constructor? I would like to decorate JUnit's ResultPrinter but am getting an error about the missing constructor.
I don't understand your issue. I just tried this with Java's Short — which also does not have a default constructor.
Everything worked as expected, except if you didn't initialize the delegated object, you get an NPE.
Is it possible you are using #Delegate incorrectly? Delegate doesn't decorate existing classes, it allows you to use an existing classes methods in your own class. It's like extend, but without the class inheritance.
Example code:
class Foo {
#Delegate Short num
String bar
String toString() { "$bar: $num" }
}
def f = new Foo(bar: 'bob', num: 34 as Short)
println f // OK
println f.doubleValue() // OK
f = new Foo()
println f.doubleValue() // NPE
(Alternatively, providing some useful information, such as the actual error and stacktrace, and example code, will get you more useful responses.)

Groovy adding code to a constructor

Is there a way in Groovy that I can add code to a constructor when a class is instantiated? I have a Groovy class (but I can't modify the source of this particular one), but I was hoping there was a way to inject code (maybe via the metaclass) so my code gets run as part of the constructor (in this case there is only one, default constructor).
Thanks,
Jeff
You can override the constructor, but it's a little tricky, particularly if you're overriding the default constructor. You need to assign a closure to the class's metaClass.constructor, and the closure should return a new instance. The tricky part is that if you call the constructor you've overriden, you'll get into a recursive loop and generate a stack overflow. You need another way to get an instance of the class, such as a different constructor.
For testing, it's sometimes possible to get around this limitation. Usually, it's enough to first instantiate an object, then override the constructor to return the existing instance. Example:
class MyObject {
String something
MyObject() { something = "initialized" }
}
testInstance = new MyObject()
testInstance.something = "overriden"
MyObject.metaClass.constructor = { -> testInstance }
aNewObject = new MyObject()
assert aNewObject.is(testInstance)
assert aNewObject.something == "overriden"
It is possible to add new constructors or replace the old one. If you need the original constructor, you can use reflection for that:
MyObject.metaClass.constructor = { -> // for the no-arg ctor
// use reflection to get the original constructor
def constructor = MyObject.class.getConstructor()
// create the new instance
def instance = constructor.newInstance()
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
Note that you have to change this if you have parameters to your constructors, e.g:
// Note that the closure contains the signature of the constructor
MyObject.metaClass.constructor = { int year, String reason ->
def constructor = MyObject.class.getConstructor(Integer.TYPE, String.class)
def instance = constructor.newInstance(
2014, "Boy, am I really answering a question three years old?")
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
PS: Note that when you want to add constructors which are not yet existent, use the << operator instead: MyObject.metaClass.constructor << { /* as above */ }.
You can bypass the limitations in the solution proposed by storing the original constructor using standard Java reflection. For example, this is what I do initialize a class (basic injection) in a spock test:
def setupSpec() {
MockPlexusContainer mockPlexusContainer = new MockPlexusContainer()
def oldConstructor = MY_CLASS.constructors[0]
MY_CLASS.metaClass.constructor = { ->
def mojo = oldConstructor.newInstance()
mockPlexusContainer.initializeContext(mojo)
return mojo
}
}
This gets invoked only once, but eveytime someone calls a constructor I get a different instance avoiding cleaning values and ensuring thread safety.

Resources