groovy

NullpointerException occurs when unboxing boolean Java return type where no return value specified from Java interface implemented in Groovy

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: 1.0-JSR-5
  • Fix Version/s: 1.1-rc-1
  • Component/s: class generator
  • Labels:
    None
  • Environment:
    JDK1.5 Groovy JSR 05 snapshot
  • Number of attachments :
    0

Description

Implementing a Java interface in Groovy, and forgetting to set the return value / having the return value set to void causes an NPE instead of a meaningful script compilation error.

Example:

import org.springframework.web.servlet.handler.*;
import javax.servlet.http.*

class Interceptor1 extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest httpServletRequest,
        HttpServletResponse httpServletResponse,
        Object object) {
        httpServletRequest.setAttribute( "something", "somevalue")
        // return true;
    }
}

The above causes an NPE when you call preHandle on this object, the NPE is the result of a failure to unbox the boolean, presumably as it has been set no value.

This is of course correct but it is a very obscure problem and definitely needs a sensible compile-time error message and exception, of the form "No value has been returned from method XXXX which should return a YYYYY"

Activity

Hide
John Wilson added a comment -

This is intended behaviour.

Groovy allows you to return null when the return type of the method is a primative and Groovy returns null when there is no expilicit return statement.

It's arguable that the correct behaviour in this case is for the null to be interpreted as false which is the default behaviour when null is treated as a Boolean

Show
John Wilson added a comment - This is intended behaviour. Groovy allows you to return null when the return type of the method is a primative and Groovy returns null when there is no expilicit return statement. It's arguable that the correct behaviour in this case is for the null to be interpreted as false which is the default behaviour when null is treated as a Boolean
Hide
Marc Palmer added a comment -

Hold on a sec - I wouldn't say this means it is resolved.

Your last sentence says it all - it must either be treated as false or it must throw a sensible exception so the user knows what the hell is going on!

So which is it going to be? I don't want this issue to disappear, I took the time to report it because the confusing error message caused me problems finding the (simple) answer.

Show
Marc Palmer added a comment - Hold on a sec - I wouldn't say this means it is resolved. Your last sentence says it all - it must either be treated as false or it must throw a sensible exception so the user knows what the hell is going on! So which is it going to be? I don't want this issue to disappear, I took the time to report it because the confusing error message caused me problems finding the (simple) answer.
Hide
John Wilson added a comment -

It would be helpful to have slightly more context:

If the method is returning back to a Java program then you are just going to get an NPE I'm afraid. Calling Groovy methods from Java can sometimes produce suprising results (e.g. you can get a checked exception thrown even though there's no throws declaration).

The method should not convert the null to false because Groovy code can quite validy look for the null value rather than false.

If the method is returning back to Groovy then you really should not get an NPE. Boxing/unboxing booleans should deal with nulls gracefully.

def boolean b(() {}

if (!b()) prinln "OK"

this currently throws an NPE and should not (I'm about to raise an issue about that)

So we can and will fix this problem when the call is made from groovy but can't and won't fix it when the call is made from Java.

I hope that clarifies the situation.

Show
John Wilson added a comment - It would be helpful to have slightly more context: If the method is returning back to a Java program then you are just going to get an NPE I'm afraid. Calling Groovy methods from Java can sometimes produce suprising results (e.g. you can get a checked exception thrown even though there's no throws declaration). The method should not convert the null to false because Groovy code can quite validy look for the null value rather than false. If the method is returning back to Groovy then you really should not get an NPE. Boxing/unboxing booleans should deal with nulls gracefully. def boolean b(() {} if (!b()) prinln "OK" this currently throws an NPE and should not (I'm about to raise an issue about that) So we can and will fix this problem when the call is made from groovy but can't and won't fix it when the call is made from Java. I hope that clarifies the situation.
Hide
Marc Palmer added a comment -

Hmm, I see.

However, surely there is more we can do. Can't we produce a warning to a log when Groovy class X is called with no return value set in a method? It would seem a really bad programming style to rely on a void return type evaluating to something meaningful surely?

I think it just leaves open a source of really obscure bugs - especially when interacting with Java as you say.

I personally think that if no return value has been specified at all (the last expression evaluated to void) then I don't think it is right for the code to run without an exception. It's bad style - and how hard is it to write:

boolean someMethod()
{
callSomeVoidMethod()
false
}

Surely that is better than null --> false, as "null" assumes you know that the return type would be null and not some meta-value "void"

Show
Marc Palmer added a comment - Hmm, I see. However, surely there is more we can do. Can't we produce a warning to a log when Groovy class X is called with no return value set in a method? It would seem a really bad programming style to rely on a void return type evaluating to something meaningful surely? I think it just leaves open a source of really obscure bugs - especially when interacting with Java as you say. I personally think that if no return value has been specified at all (the last expression evaluated to void) then I don't think it is right for the code to run without an exception. It's bad style - and how hard is it to write: boolean someMethod() { callSomeVoidMethod() false } Surely that is better than null --> false, as "null" assumes you know that the return type would be null and not some meta-value "void"
Hide
John Wilson added a comment -

I think you have raised an interesting point. I have written an email for the dev list to try to get imput from some of the other developers. I can't post it yet as I'm behind a rather stict firewall. I'll post it in a couple of hours when I'm back at my hotel. Please feel free to contibute to the thread

Show
John Wilson added a comment - I think you have raised an interesting point. I have written an email for the dev list to try to get imput from some of the other developers. I can't post it yet as I'm behind a rather stict firewall. I'll post it in a couple of hours when I'm back at my hotel. Please feel free to contibute to the thread
Hide
Paul King added a comment -

Seems to be resolved. This Groovy script:

class MyClass implements MyInterface {
    public boolean foo() {
        println 'nothing interesting here'
    }
}

println new MyClass().foo()

with this Java interface:

public interface MyInterface {
    boolean foo();
}

yields

nothing interesting here
false

Similarly, calling from Java as follows yields the same result:

public class MyMain {
    public static void main(String[] args){
        boolean b = new MyClass().foo();
        System.out.println("b = " + b);
    }
}

Well, almost:

nothing interesting here
b = false
Show
Paul King added a comment - Seems to be resolved. This Groovy script:
class MyClass implements MyInterface {
    public boolean foo() {
        println 'nothing interesting here'
    }
}

println new MyClass().foo()
with this Java interface:
public interface MyInterface {
    boolean foo();
}
yields
nothing interesting here
false
Similarly, calling from Java as follows yields the same result:
public class MyMain {
    public static void main(String[] args){
        boolean b = new MyClass().foo();
        System.out.println("b = " + b);
    }
}
Well, almost:
nothing interesting here
b = false

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: