I feel a bit silly for making this question, but I'm out of options.
Basically, I have this on a "let's learn groovy" project:
package com.mypackage.markupexercise
import groovy.xml.MarkupBuilder
println "Hello MarkupBuilder"
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.records() {
example(id:1)
}
And I'm getting the following compilation error:
<path>\markupbuilderexercise\Main.groovy: 3: unable to resolve class groovy.xml.MarkupBuilder
# line 3, column 1.
import groovy.xml.MarkupBuilder
^
1 error
Now, I've seen [this question][1], and I have imported the groovy-xml-3.09.jar file (Through right click on project -> Properties -> Java Build Path -> Add Jars...)
There is nothing on the "Problems" tab, and if I try to run through the groovy console, I get the following error:
groovy.lang.MissingMethodException: No signature of method: groovy.xml.MarkupBuilder.records() is applicable for argument types: (com.neuro.groovyhelloworld.markupbuilderexercise.Main$_run_closure1) values: [com.neuro.groovyhelloworld.markupbuilderexercise.Main$_run_closure1#2e757861]
at com.neuro.groovyhelloworld.markupbuilderexercise.Main.run(Main.groovy:10)
at com.neuro.groovyhelloworld.markupbuilderexercise.Main.main(Main.groovy)
My take here is that I'm not adding the dependency in the right way, but I'm a Java developer and dependencies were either what I've done or just relying on Maven/Gradle, so I'm kind of out of ideas here.
What am I missing?
[1]: https://stackoverflow.com/questions/59132101/eclipse-groovy-unable-to-resolve-class
I see the same issue when choosing Run As > Groovy Console and then running the script. It does work fine for Run As > Groovy Script on the following source -- I used grab so I didn't need to add groovy-xml to my project's classpath:
#Grab('org.codehaus.groovy:groovy-xml:3.0.9')
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
new MarkupBuilder(writer).tap {
records {
example(id:1)
}
}
print writer
I get the following output:
<records>
<example id='1' />
</records>
You can also build the project and run the script using Run As > Java Application.
Given is a class EnumTest that declares an inner enum MyEnum.
Using MyEnum as parameter type from within the class works as expected.
Using MyEnum as a parameter type outside of EnumTest fails to compile with unable to resolve class test.EnumTest.MyEnum.
I've browsed related questions, of which the best one was this, but they didn't address the specific issue of using the enum as a type.
Am I missing something very obvious here (as I'm very new to Groovy)? Or is this just another of the language's quirks "enhancements" regarding enums?
Edit: This is just a test demonstrating the issue. The actual issue happens in Jenkins JobDSL, and classpaths and imports seem to be fine there otherwise.
Groovy Version: 2.4.8
JVM: 1.8.0_201
Vendor: Oracle Corporation
OS: Linux
$ tree test
test
├── EnumTest.groovy
├── File2.groovy
└── File3.groovy
EnumTest.groovy:
package test
public class EnumTest {
public static enum MyEnum {
FOO, BAR
}
def doStuff(MyEnum v) {
println v
}
}
File2.groovy:
package test
import test.EnumTest
// prints BAR
new EnumTest().doStuff(EnumTest.MyEnum.BAR)
// prints FOO
println EnumTest.MyEnum.FOO
File3.groovy:
package test
import test.EnumTest
// fails: unable to resolve class test.EnumTest.MyEnum
def thisShouldWorkIMHO(EnumTest.MyEnum v) {
println v
}
When I'm running the test files using groovy -cp %, the output is as follows:
# groovy -cp . File2.groovy
BAR
FOO
# groovy -cp . File3.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/home/lwille/-/test/GroovyTest2.groovy: 6: unable to resolve class EnumTest.MyEnum
# line 6, column 24.
def thisShouldWorkIMHO(EnumTest.MyEnum v) {
^
1 error
A few things worth mentioning. You don't need to import classes from the same package. Secondly, when you use a package test then you need to execute Groovy from the root folder, e.g. groovy test/File3.groovy to properly set up the classpath. (There is no need to use -cp . in such case).
Here's what it should look like.
$ tree test
test
├── EnumTest.groovy
├── File2.groovy
└── File3.groovy
0 directories, 3 files
test/EnumTest.groovy
package test
public class EnumTest {
public static enum MyEnum {
FOO, BAR
}
def doStuff(MyEnum v) {
println v
}
}
test/File2.groovy
package test
// prints BAR
new EnumTest().doStuff(EnumTest.MyEnum.BAR)
// prints FOO
println EnumTest.MyEnum.FOO
test/File3.groovy
package test
// fails: unable to resolve class test.EnumTest.MyEnum
def thisShouldWorkIMHO(EnumTest.MyEnum v) {
println v
}
thisShouldWorkIMHO(EnumTest.MyEnum.BAR)
The console output:
$ groovy test/File2.groovy
BAR
FOO
$ groovy test/File3.groovy
BAR
However, if you want to execute script from inside the test folder then you need to specify the classpath to point to the parent folder, e.g.:
$ groovy -cp ../. File3.groovy
BAR
$ groovy -cp . File3.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/home/wololock/workspace/groovy-sandbox/src/test/File3.groovy: 4: unable to resolve class EnumTest.MyEnum
# line 4, column 24.
def thisShouldWorkIMHO(EnumTest.MyEnum v) {
^
1 error
UPDATE: the difference between Groovy 2.4 and 2.5 versions
One thing worth mentioning - the above solution works for Groovy 2.5.x and above. It is important to understand that things like methods parameters type check happen at the compiler's Phase.SEMANTIC_ANALYSIS phase. In Groovy 2.4 version, semantic analysis class resolving happens without loading classes. In case of using an inner class, it is critical to load its outer class so it can get resolved. Groovy 2.5 fixed that problem (intentionally or not) and semantic analysis resolves inner classes without an issue mentioned in this question.
For more detailed analysis, please check the following Stack Overflow question GroovyScriptEngine throws MultipleCompilationErrorsException while loading class that uses other class' static inner class where I have investigated a similar issue found in a Groovy 2.4 script. I explained there step by step how to dig down to the roots of this problem.
For some reason, I get this error message whenever I try to compile this simple function: Test.hx:1: lines 1-7 : Invalid -main : Test has invalid main function
public static function main(a:Int, b:Int){
trace("Calling main function");
return a+b;
}
I'm not sure why this is happening. What's wrong with this function definition, and how can I get it to compile correctly? I tried reading the documentation, and found it to be unclear in its explanation of how to properly set function return types.
The special main entry function must be a Void->Void function. i.e. No param and no return value is allowed. Remember there is no command line argument concept in JS/Flash, which Haxe also compiles to. So we have to use system targets' API for that:
Sys.args() : Array<String> to get the command line params.
Sys.exit( code : Int ) : Void to exit with exit code.
FYI, the doc of Sys is at http://haxe.org/api/sys
Just started learning Groovy, got the PragProg book "Programming Groovy" and had a problem compiling one of the sample scripts:
class GCar2 {
final miles = 0
def getMiles() {
println "getMiles called"
miles
}
def drive(dist) {
if (dist > 0) {
miles += dist
}
}
}
def car = new GCar2()
println "Miles: $car.miles"
println 'Driving'
car.drive(10)
println "Miles: $car.miles"
try {
print 'Can I see the miles? '
car.miles = 12
} catch (groovy.lang.ReadOnlyPropertyException ex) {
println ex.message
GroovyCar2.groovy: 20: cannnot access final field or property outside of constructor.
# line 20, column 35.
def drive(dist) { if (dist > 0) miles += dist }
^
Groovy versions prior to 1.7 do not give an error. I looked through whatever documentation I could find and did not see the issue discussed. What is going on here?
Aaron
I don't know much about Groovy 1.7, but it looks like a bug in earlier versions which has now been fixed - if a variable is final, you shouldn't be able to assign to it outside the constructor (or its declaration). If you can, what's the point of making it final?
I doubt that it'll stop you from reading it outside the constructor though...
You shouldn't be able to assign to a final variable in a normal method. It was a bug in groovy, fixed in 1.7.
In Ruby, objects have a handy method called method_missing which allows one to handle method calls for methods that have not even been (explicitly) defined:
Invoked by Ruby when obj is sent a message it cannot handle. symbol is the symbol for the method called, and args are any arguments that were passed to it. By default, the interpreter raises an error when this method is called. However, it is possible to override the method to provide more dynamic behavior. The example below creates a class Roman, which responds to methods with names consisting of roman numerals, returning the corresponding integer values.
class Roman
def romanToInt(str)
# ...
end
def method_missing(methId)
str = methId.id2name
romanToInt(str)
end
end
r = Roman.new
r.iv #=> 4
r.xxiii #=> 23
r.mm #=> 2000
For example, Ruby on Rails uses this to allow calls to methods such as find_by_my_column_name.
My question is, what other languages support an equivalent to method_missing, and how do you implement the equivalent in your code?
Smalltalk has the doesNotUnderstand message, which is probably the original implementation of this idea, given that Smalltalk is one of Ruby's parents. The default implementation displays an error window, but it can be overridden to do something more interesting.
PHP objects can be overloaded with the __call special method.
For example:
<?php
class MethodTest {
public function __call($name, $arguments) {
// Note: value of $name is case sensitive.
echo "Calling object method '$name' "
. implode(', ', $arguments). "\n";
}
}
$obj = new MethodTest;
$obj->runTest('in object context');
?>
Some use cases of method_missing can be implemented in Python using __getattr__ e.g.
class Roman(object):
def roman_to_int(self, roman):
# implementation here
def __getattr__(self, name):
return self.roman_to_int(name)
Then you can do:
>>> r = Roman()
>>> r.iv
4
I was looking for this before, and found a useful list (quickly being overtaken here) as part of the Merd project on SourceForge.
Construct Language
----------- ----------
AUTOLOAD Perl
AUTOSCALAR, AUTOMETH, AUTOLOAD... Perl6
__getattr__ Python
method_missing Ruby
doesNotUnderstand Smalltalk
__noSuchMethod__(17) CoffeeScript, JavaScript
unknown Tcl
no-applicable-method Common Lisp
doesNotRecognizeSelector Objective-C
TryInvokeMember(18) C#
match [name, args] { ... } E
the predicate fail Prolog
forward Io
With footnotes:
(17) firefox
(18) C# 4, only for "dynamic" objects
JavaScript has noSuchMethod, but unfortunately this is only supported by Firefox/Spidermonkey.
Here is an example:
wittyProjectName.__noSuchMethod__ = function __noSuchMethod__ (id, args) {
if (id == 'errorize') {
wittyProjectName.log("wittyProjectName.errorize has been deprecated.\n" +
"Use wittyProjectName.log(message, " +
"wittyProjectName.LOGTYPE_ERROR) instead.",
this.LOGTYPE_LOG);
// just act as a wrapper for the newer log method
args.push(this.LOGTYPE_ERROR);
this.log.apply(this, args);
}
}
Perl has AUTOLOAD which works on subroutines & class/object methods.
Subroutine example:
use 5.012;
use warnings;
sub AUTOLOAD {
my $sub_missing = our $AUTOLOAD;
$sub_missing =~ s/.*:://;
uc $sub_missing;
}
say foo(); # => FOO
Class/Object method call example:
use 5.012;
use warnings;
{
package Shout;
sub new { bless {}, shift }
sub AUTOLOAD {
my $method_missing = our $AUTOLOAD;
$method_missing =~ s/.*:://;
uc $method_missing;
}
}
say Shout->bar; # => BAR
my $shout = Shout->new;
say $shout->baz; # => BAZ
Objective-C supports the same thing and calls it forwarding.
This is accomplished in Lua by setting the __index key of a metatable.
t = {}
meta = {__index = function(_, idx) return function() print(idx) end end}
setmetatable(t, meta)
t.foo()
t.bar()
This code will output:
foo
bar
In Common Lisp, no-applicable-method may be used for this purpose, according to the Common Lisp Hyper Spec:
The generic function no-applicable-method is called when a generic function is invoked and no method on that generic function is applicable. The default method signals an error.
The generic function no-applicable-method is not intended to be called by programmers. Programmers may write methods for it.
So for example:
(defmethod no-applicable-method (gf &rest args)
;(error "No applicable method for args:~% ~s~% to ~s" args gf)
(%error (make-condition 'no-applicable-method :generic-function gf :arguments args) '()
;; Go past the anonymous frame to the frame for the caller of the generic function
(parent-frame (%get-frame-ptr))))
C# now has TryInvokeMember, for dynamic objects (inheriting from DynamicObject)
Actionscript 3.0 has a Proxy class that can be extended to provide this functionality.
dynamic class MyProxy extends Proxy {
flash_proxy override function callProperty(name:*, ...rest):* {
try {
// custom code here
}
catch (e:Error) {
// respond to error here
}
}
Tcl has something similar. Any time you call any command that can't be found, the procedure unknown will be called. While it's not something you normally use, it can be handy at times.
In CFML (ColdFusion, Railo, OpenBD), the onMissingMethod() event handler, defined within a component, will receive undefined method calls on that component. The arguments missingMethodName and missingMethodArguments are automatically passed in, allowing dynamic handling of the missing method call. This is the mechanism that facilitated the creation of implicit setter/getter schemes before they began to be built into the various CFML engines.
Its equivalent in Io is using the forward method.
From the docs:
If an object doesn't respond to a message, it will invoke its "forward" method if it has one....
Here is a simple example:
Shout := Object clone do (
forward := method (
method_missing := call message name
method_missing asUppercase
)
)
Shout baz println # => BAZ
/I3az/
Boo has IQuackFu - there is already an excellent summary on SO at how-can-i-intercept-a-method-call-in-boo
Here is an example:
class XmlObject(IQuackFu):
_element as XmlElement
def constructor(element as XmlElement):
_element = element
def QuackInvoke(name as string, args as (object)) as object:
pass # ignored
def QuackSet(name as string, parameters as (object), value) as object:
pass # ignored
def QuackGet(name as string, parameters as (object)) as object:
elements = _element.SelectNodes(name)
if elements is not null:
return XmlObject(elements[0]) if elements.Count == 1
return XmlObject(e) for e as XmlElement in elements
override def ToString():
return _element.InnerText