Groovy "not instanceof" peculiarity - groovy

I have discovered behaviour that I hadn't anticipated within Groovy 2.4.7, 1.6.0 JVM when attempting to evaluate a not instanceof condition.
in summary:
class Foo {
static Boolean bar() {
String x = "Personally, I don't really like King Crimson"
return (!x instanceof Integer)
}
}
I would anticipate that Foo.bar() would return true because x is not an instance of Integer however Foo.bar() returns false. In contrast the following returns true:
class Foo {
static Boolean bar() {
String x = "Personally, I don't really like King Crimson"
return !(x instanceof Integer)
}
}
The issue is academic, but out of curiousity: is this a bug in the language or have I misunderstood how instanceof is supposed to work?

It's a case of operator precedence...
! occurs before instanceof, so it's actually checking:
(!x) instanceof Integer
So it's converting String to a boolean (!'Hello' is false as the string contains some text.
Then seeing if the boolean is an instanceof Integer (which it isn't)
hence false
If you put the ! outside the brackets (as in your second version) then it does the instanceof first, and negates the result, giving you the answer you'd expect
Edit for Groovy 3+
In groovy 3 there's a new way of doing this using !instanceof:
return x !instanceof Integer

Related

java.lang.IllegalArgumentException: wrong number of arguments at javax.faces.component.UIComponentBase.isRendered [duplicate]

I'm using JSF 2.
I have a method that checks for matching values from a list of values:
#ManagedBean(name="webUtilMB")
#ApplicationScoped
public class WebUtilManagedBean implements Serializable{ ...
public static boolean isValueIn(Integer value, Integer ... options){
if(value != null){
for(Integer option: options){
if(option.equals(value)){
return true;
}
}
}
return false;
}
...
}
To call this method in EL I tried:
#{webUtilMB.isValueIn(OtherBean.category.id, 2,3,5)}
But it gave me a:
SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments
Is there a way to execute such a method from EL?
No, it is not possible to use variable arguments in EL method expressions, let alone EL functions.
Your best bet is to create multiple different named methods with a different amount of fixed arguments.
public static boolean isValueIn2(Integer value, Integer option1, Integer option2) {}
public static boolean isValueIn3(Integer value, Integer option1, Integer option2, Integer option3) {}
public static boolean isValueIn4(Integer value, Integer option1, Integer option2, Integer option3, Integer option4) {}
// ...
As a dubious alternative, you could pass a commaseparated string and split it inside the method
#{webUtilMB.isValueIn(OtherBean.category.id, '2,3,5')}
or even a string array which is created by fn:split() on a commaseparated string
#{webUtilMB.isValueIn(OtherBean.category.id, fn:split('2,3,5', ','))}
but either way, you'd still need to parse them as integer, or to convert the passed-in integer to string.
In case you're already on EL 3.0, you could also use the new EL 3.0 collection syntax without the need for the whole EL function.
#{[2,3,5].contains(OtherBean.category.id)}

Range ordering and inequality comparison

I was trying to recreate Python's range as a learning exercise, and noticed that ranges had range.__gt__, range.__ge__ etc. attribute. It was specifically defined in range, as range also has 8 attributes with the qualified name of object.__...__.
I was wondering what the range comparisons are used for. Any attempt at range(*x) <= range(*y) raises a TypeError: unorderable types: range() > range()
The Python 3 range object defines the following rich comparisons (taken from the C source):
static PyObject *
range_richcompare(PyObject *self, PyObject *other, int op)
{
int result;
if (!PyRange_Check(other))
Py_RETURN_NOTIMPLEMENTED;
switch (op) {
case Py_NE:
case Py_EQ:
result = range_equals((rangeobject*)self, (rangeobject*)other);
if (result == -1)
return NULL;
if (op == Py_NE)
result = !result;
if (result)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
case Py_LE:
case Py_GE:
case Py_LT:
case Py_GT:
Py_RETURN_NOTIMPLEMENTED;
default:
PyErr_BadArgument();
return NULL;
}
}
As you can see, the only comparisons that are actually implemented are NE and EQ which are for inequality and equality. The other comparisons, like larger-equals, larger-than, etc., are all Py_RETURN_NOTIMPLEMENTED, so while they are “technically” implemented (as in the builtin object defines the comparison methods), they throw a NotImplementedError.

Comparing strings inside of two objects

I've been trying to compare the string inside of the Card() object with the other Card() objects to check for duplicates when the playing cards are dealt.
Except when printing out the compare statement i'm getting something like Card#97sd829. I made my own Equals() method for comparison of the object Card() inside of the Class but still to no avail.
I've tried using the override of the equals() object but I'm getting an error saying it needs to be inside of a superclass?
public static boolean Equals(Card a, Card b) {
String str1 = a.toString();
String str2 = b.toString();
if (str1.equals(str2))
return true;
else
return false;
}
public static boolean checkDuplicate (Card a, Card b, Card c, Card d, Card e){
int num = 5;
boolean bool = true;
if (Card.Equals(a, b)||Card.Equals(a, c)||Card.Equals(a, d)||Card.Equals(a, e)||
Card.Equals(b, c)||Card.Equals(b, d)||Card.Equals(b, e)||Card.Equals(c, d)||
Card.Equals(c, e)||Card.Equals(d, e)); num--;
if (num == 5)
bool = false;
else
bool = true;
return bool;
}
You are using the toString() method of the Object.class to get a String representation of your cards.
The default implementation of toString() contains the hash of the object. Since you have two different Card-objects the toString() method of these objects produces different output.
A better way would be to implement equals() in the Card class. Then you could check for equality with a.equals(b).
If you want advice how to implement Card.equals() you should post the source code of the Card class.

How do I use groovy's AS keyword

This may be a duplicate but "as" is an INCREDABLY hard keyword to google, even S.O. ignores "as" as part of query.
So I'm wondering how to implement a class that supports "as" reflexively. For an example class:
class X {
private val
public X(def v) {
val=v
}
public asType(Class c) {
if (c == Integer.class)
return val as Integer
if(c == String.class)
return val as String
}
}
This allows something like:
new X(3) as String
to work, but doesn't help with:
3 as X
I probably have to attach/modify the "asType" on String and Integer somehow, but I feel any changes like this should be confined to the "X" class... Can the X class either implement a method like:
X fromObject(object)
or somehow modify the String/Integer class from within X. This seems tough since it won't execute any code in X until X is actually used... what if my first usage of X is "3 as X", will X get a chance to override Integer's asType before Groovy tries to call is?
As you say, it's not going to be easy to change the asType method for Integer to accept X as a new type of transformation (especially without destroying the existing functionality).
The best I can think of is to do:
Integer.metaClass.toX = { -> new X( delegate ) }
And then you can call:
3.toX()
I can't think how 3 as X could be done -- as you say, the other way; new X('3') as Integer is relatively easy.
Actually, you can do this:
// Get a handle on the old `asType` method for Integer
def oldAsType = Integer.metaClass.getMetaMethod( "asType", [Class] as Class[] )
// Then write our own
Integer.metaClass.asType = { Class c ->
if( c == X ) {
new X( delegate )
}
else {
// if it's not an X, call the original
oldAsType.invoke( delegate, c )
}
}
3 as X
This keeps the functionality out of the Integer type, and minimizes scope of the effect (which is good or bad depending on what you're looking for).
This category will apply asType from the Integer side.
class IntegerCategory {
static Object asType(Integer inty, Class c) {
if(c == X) return new X(inty)
else return inty.asType(c)
}
}
use (IntegerCategory) {
(3 as X) instanceof X
}

How to truncate a string in groovy?

How to truncate string in groovy?
I used:
def c = truncate("abscd adfa dasfds ghisgirs fsdfgf", 10)
but getting error.
The Groovy community has added a take() method which can be used for easy and safe string truncation.
Examples:
"abscd adfa dasfds ghisgirs fsdfgf".take(10) //"abscd adfa"
"It's groovy, man".take(4) //"It's"
"It's groovy, man".take(10000) //"It's groovy, man" (no exception thrown)
There's also a corresponding drop() method:
"It's groovy, man".drop(15) //"n"
"It's groovy, man".drop(5).take(6) //"groovy"
Both take() and drop() are relative to the start of the string, as in "take from the front" and "drop from the front".
Online Groovy console to run the examples:
https://ideone.com/zQD9Om — (note: the UI is really bad)
For additional information, see "Add a take method to Collections, Iterators, Arrays":
https://issues.apache.org/jira/browse/GROOVY-4865
In Groovy, strings can be considered as ranges of characters. As a consequence, you can simply use range indexing features of Groovy and do myString[startIndex..endIndex].
As an example,
"012345678901234567890123456789"[0..10]
outputs
"0123456789"
we can simply use range indexing features of Groovy and do someString[startIndex..endIndex].
For example:
def str = "abcdefgh"
def outputTrunc = str[2..5]
print outputTrunc
Console:
"cde"
To avoid word break you can make use of the java.text.BreakIterator. This will truncate a string to the closest word boundary after a number of characters.
Example
package com.example
import java.text.BreakIterator
class exampleClass {
private truncate( String content, int contentLength ) {
def result
//Is content > than the contentLength?
if(content.size() > contentLength) {
BreakIterator bi = BreakIterator.getWordInstance()
bi.setText(content);
def first_after = bi.following(contentLength)
//Truncate
result = content.substring(0, first_after) + "..."
} else {
result = content
}
return result
}
}
Here's my helper functions to to solve this kinda problem. In many cases you'll probably want to truncate by-word rather than by-characters so I pasted the function for that as well.
public static String truncate(String self, int limit) {
if (limit >= self.length())
return self;
return self.substring(0, limit);
}
public static String truncate(String self, int hardLimit, String nonWordPattern) {
if (hardLimit >= self.length())
return self;
int softLimit = 0;
Matcher matcher = compile(nonWordPattern, CASE_INSENSITIVE | UNICODE_CHARACTER_CLASS).matcher(self);
while (matcher.find()) {
if (matcher.start() > hardLimit)
break;
softLimit = matcher.start();
}
return truncate(self, softLimit);
}

Resources