I have an abstract java class which has a constructor and I'm extending it from a groovy class. (the idea is to keep the java class as a contract inside the app and load external groovy classes that implement certain constructors and methods)
How can I force in Groovy to implement an abstract super class's constructor?
Does Groovy allow to force the implementation of the abstract parent class's constructor?
The thing is that the Eclipse Groovy IDE is not forcing me to implement the constructor of the parent class in the subclass, I thougth Groovy would create it automatically and so that was the reason to not forcing it. However at run time when trying to get the constructor using java reflection fails it fails if I don't define the parent constructor in the subclass.
(I have 0 experience in Groovy)
It looks like an unchecked situation in the compiler. Upon decompiling, the extending class gets an empty constructor. Tests should get you covered, since this situation doesn't work in runtime.
I don't know of a way to use this class; i tried the ways i know:
abstract class AbstractClass {
String string
Integer integer
AbstractClass(String string, Integer integer) {
this.string = string
this.integer = integer
}
}
class ImplClass extends AbstractClass { }
// every constructor fails
abs1 = new ImplClass('a', 1)
abs2 = [string: 'b', integer: 2] as ImplClass
abs3 = new ImplClass(abs: 'c', a: 3)
abs4 = ImplClass [string:'d', integer:4]
Neither of them worked in runtime, but compiled fine ;-). The situation is more about compile error vs runtime error. Maybe filling a JIRA?
On the other way around, if you needed to inherit the constructors, you could go for #groovy.transfom.InheritConstructors in the extending class. This way you would have the constructors without needing to call super() explicitly.
Related
I am working on a shared library for Jenkins, and I want to access some utilities methods between some classes, but not all of them, thus I have established some statements:
I would like to avoid using static methods, since it does not access pipeline steps directly, and passing the pipeline instance every call would be a pain;
I would like to avoid a singleton as well, or prefixing every method call with the util class' instance;
Since it is not supposed to be shared between all classes I would like to avoid putting every method as a file on vars/ special directory, but I would like a similar behavior;
Despite extending the class would be a anti-pattern, it would be acceptable, though I would like to avoid the verbose Java syntax for declaring the class the same name as the file, once it is implicit in groovy;
This question does solve my problem partially, although there are issues with serialization, I noted that when I use checkpoint and some build is resumed from some stage, the instance loses all extra methods.
This other question would have helped me fix the serialization issue, however the author seems the have solved the root cause of his problem using a way that is not the original question titled for.
Is there a way to extends a implicit script class in groovy without using the class NameOfFile extends SomeOtherClass { put every thing inside this block } syntax? And without working with inner-class?
Or else, is there a way to declare a constructor using the script groovy syntax analogue as the previous question?
Or even, is there a way to change the serialization behavior to install the extra methods again after unserializing?
Appendix
The script syntax works more-or-less like this:
Consider the content of file src/cicd/pipeline/SomePipeline.groovy:
package cicd.pipeline
// there is no need to wrap everything inside class SomePipeline,
// since it is implicit
def method() {
// instance method, here I can access pipeline steps freely
}
def static otherMethod() {
// static method, here it is unable to access pipeline steps
// without a instance
}
#groovy.transform.Field
def field
def call() {
// if the class is used as method it will run
this.method()
SomePipeline.otherMethod() // or simply otherMethod() should work
this.field = 'foo'
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
}
// any code other than methods or variables with #Field
// annotation will be inside a implicit run method that is
// triggered likewise main method but isn't a static one
def localVar = 'foo'
println "It will not execute on constructor since it is on run: $localVar"
println "Method: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Throwable()).stackTrace[0].methodName}"
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
If I was going to use the Java verbose syntax I would have to wrap almost everything inside a class SomePipeline which is implicit in groovy, this is the script syntax I want to keep.
I realised that this.getClass().superclass.canonicalName when outside Jenkins pipeline is groovy.lang.Script and when inside pipeline is org.jenkinsci.plugins.workflow.cps.CpsScript and based on this resource I was able to elaborate the following solution:
abstract class CustomScript extends org.jenkinsci.plugins.workflow.cps.CpsScript {
public CustomScript() {
// do something here, it will always execute regardless
// serialization, and before everything
}
}
#groovy.transform.BaseScript CustomScript baseScript
That is it, worked as expected! Of course you can elaborate this solution better in order to reduce repeating and avoid inner-classes, but I will leave it for your imagination.
I've got a rendering engine, much like React where I need to store classes rather than instances in an object for compiling.
So for example, I have a Button component that I would like to be able to dynamically instantiate. Doing this would be as easy as
new components["Button"]
For this, I need a list of all possible classes. So I've got a Dictionary interface declared like so:
interface Dictionary<T> {
[Key: string]: T;
}
This works well, I'm easily able to add objects to this dictionary. Except if I have an object:
const components: Dictionary<Component> = {
Button: Button
}
Then I get an error because Button is a class, rather than an instance. Here, the issue is, I don't want to define the dictionary as Dictionary<Function> because that would mean I allow any function into the dictionary. Specifically, I only want to allow classes into the dictionary that extend the Component class.
How would I achieve this?
You also need to define the signature of the constructor (which makes sense if you think about it), but you do the following:
interface ComponentClass {
new (a: number): Component;
}
(The signature of the constructor is probably not "number", but put in whatever it is.)
I would like to be able to use plain java-style implicit/explicit casting instead of asType overrides so that sources written in Java work properly. I've overridden asType on String similarly to the approach suggested in How to overload some Groovy Type conversion for avoiding try/catch of NumberFormatException? like:
oldAsType = String.metaClass.getMetaMethod("asType", [Class] as Class[])
String.metaClass.asType = {Class typ ->
if (Foo.class.isAssignableFrom(typ)) {
Foo.myCast(delegate)
} else {
oldAsType.invoke(delegate,typ)
}
}
I'd like all of these options to work:
// groovy
String barString
Foo foo = barString asType(Foo.class) // asType works but
Foo foo = barString // implicit cast fails
Foo foo = (Foo) barString // explicit cast fails
The latter two fail because groovy is using DefaultTypeTransformation.castToType, which doesn't attempt to invoke new Foo() unless the object to be cast is either one of a slew of special cases or is some sort of Collection type.
Note that the solution Can I override cast operator in Groovy? doesn't solve the issue because the code that is doing the casting is regular Java code that I cannot alter, at least not at the source code level. I'm hoping that there is either a secret hook into casting or a way to override the static castToType method (in a Java class, called by another Java class - which Can you use Groovy meta programming to override a private method on a Java class says is unsupported)... or some other clever approach I haven't thought of.
Edit: The question is about using Java-style casting syntax, essentially to use groovy facilities to add an autoboxing method. Groovy calls this mechanism "casting," for better or worse (see DefaultTypeTransformation.castToType as referenced above). In particular, I have replaced an enum with a resourced class and want to retain JSON serialization. Groovy's JSON package automatically un/marshals enum values of instance members to strings and I'm trying to make the replacement class serialize compatibly with a minimal changes to the source code.
Part of the problem here is you are confusing conversion with casting. Using the "as" operator is not the same thing as imposing a cast. They seem similar, but they serve separate purposes.
Foo foo = (Foo) barString
That doesn't say something like "create a Foo out of barString". That says "Declare a reference named foo, associate the static type Foo with that reference and then point that reference at the object on the heap that the reference barString currently points to.". Unlike languages like C++, Groovy and Java do not allow you to ever get in a situation where a reference points at an object that is of a type that is incompatible with the reference's type. If you ever got into a situation where a Foo reference was pointing to a String on the heap, that would represent a bug in the JVM. It cannot be done. You can come up with ways to create Foo objects out of String objects, but that isn't what the code above is about.
The answer appears to be "no". Absent a rewrite of the DefaultTypeTransformation.castToType to allow for this sort of metaprogramming, the implication is to use another implementation strategy or use a different language.
I mainly program in groovy, but occasionally it's too slow. So I write a separate .java class, and put the code that needs to run faster in a java method and call that java method from my groovy code.
This causes me to end up with two separate files and two separate classes. Is there any way I could embed a java method right into the groovy file, maybe marking it with an annotation to indicate that it is java?
This is the idea behind groovy++. Marking a class or method with the #Typed annotation will cause it to use static typing instead of dynamic typing, while still retaining a lot of goodness of groovy.
While not exactly java, typed groovy++ methods generally perform about the same as java would.
More information on groovy++ is available at: https://code.google.com/p/groovypptest/wiki/Welcome
You don't need to do anything special.
Just write the Java class behind the groovy class. 99% of all Java source is valid groovy source as well.
class GroovyClass {
def a;
def doSomething(x,y) { return x*y; }
}
class JavaClass {
SomeType someVar;
public JavaClass() { /* ... */ } // some contructor
public void doit(String a, int b) {} // full typed method, that is java
}
Groovy++ is somethign completely different.
The JavaClass needs to have everything fully typed to be "Java" however your problem can be solved far easyer if you just use types in the relevant groovy methods.
class AnotherGroovyClass {
// typed
public Result someMethod(SomeArg arg1, SomeOtherArg arg2) {
}
def someVariable; // untyped
}
If you think the lack of speed comes from the dynamic nature of groovy then just use full types at the relevant points.
I am using groovy to create some mock classes for a test case. I am basically creating dummy objects where all the methods return null so that i can run my testcase.
I am using the following syntax:
MessageFactory.instance = ["getMessage": {a,b,c,d -> "dummy"}] as MessageFactory
So here i am trying to overwrite the singleton instance with my on fake factory object. The problem is that MessageFactory's constructor happens to be a private method. This gives me an illigal access exception when i run the code above. Is there a away i can create a proxy in groovy and overcome the private constructor issue?
If you have access to the MessageFactory, and are willing to modify it, then you use the standard dependency-injection solution, as detailed here: mock singleton
..Though it's not particularly Groovy.
Otherwise, the best workaround I've found is to override the method(s) on the singleton instance itself, like so:
#Singleton
class Test{
def method(){"Unmocked method called"}
}
def test = Test.instance
test.metaClass.method = {-> null}
test.method() // Now returns null
Naturally, as a singleton, this instance doesn't change (at least in theory)... So, overriding methods in this manner is effectively global.
Edit: Or you can use GMock, which supports constructor mocking (among other things).