New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GroovyMock object on a final class doesn't work properly inside statically compiled service #765

Open
timic opened this Issue Sep 7, 2017 · 3 comments

Comments

Projects
None yet
2 participants
@timic

timic commented Sep 7, 2017

Issue description

GroovyMock interactions for final class doesn't work inside@CompileStatic annotated class or in plain java class. In this case mock object will use real method implementation instead of provided interaction.

Minimal code to reproduce

import groovy.transform.CompileStatic
import spock.lang.Specification

class UserServiceSpec extends Specification {
    def "test final class mock interactions"() {
        setup:
            def mock = GroovyMock(FinalClass) {
                getName() >> "Foo Bar"
            }
        when:
            new StaticService().getName(mock)
        then:
            thrown(UnsupportedOperationException)
        expect:
            new GroovyService().getName(mock) == "FOO BAR"
    }
}

final class FinalClass {
    String getName() {
        throw new UnsupportedOperationException("Not implemented")    
    }
}

class GroovyService {
    String getName(FinalClass obj) {
        obj.name.toUpperCase()
    }
}

@CompileStatic
class StaticService {
    String getName(FinalClass obj) {
        obj.name.toUpperCase()
    }
}

Environment

Java: OpenJDK Runtime Environment (build 1.8.0_144-b01)
Gradle: 3.5

Gradle dependencies

compile 'org.codehaus.groovy:groovy-all:2.4.12'
compile 'org.spockframework:spock-core:1.1-groovy-2.4'
compile 'cglib:cglib-nodep:3.2.5'
@leonard84

This comment has been minimized.

Show comment
Hide comment
@leonard84

leonard84 Sep 8, 2017

Member

GroovyMocks work via modification of the meta-class. Using static compilation will basically turn groovy bytecode into java equivalent bytecode, e.g. static binding and thus no meta-class magic.

Member

leonard84 commented Sep 8, 2017

GroovyMocks work via modification of the meta-class. Using static compilation will basically turn groovy bytecode into java equivalent bytecode, e.g. static binding and thus no meta-class magic.

@timic

This comment has been minimized.

Show comment
Hide comment
@timic

timic Sep 8, 2017

@leonard84
In this case GroovyMock works well when making FinalClass non-final. Also there is no matter whether CompileStatic over FinalClass is present or not.

timic commented Sep 8, 2017

@leonard84
In this case GroovyMock works well when making FinalClass non-final. Also there is no matter whether CompileStatic over FinalClass is present or not.

@leonard84

This comment has been minimized.

Show comment
Hide comment
@leonard84

leonard84 Sep 11, 2017

Member

@timic yes, I don't think there is anything we can do about it.

The bytecode generated for StaticService is the same whether FinalClass is indeed final or not, it uses invokevirtual in both cases. I think that the JVM is optimizing the code during load/execution, since the class is final, and inlines the address. However, I'm not an expert on this matter.

Member

leonard84 commented Sep 11, 2017

@timic yes, I don't think there is anything we can do about it.

The bytecode generated for StaticService is the same whether FinalClass is indeed final or not, it uses invokevirtual in both cases. I think that the JVM is optimizing the code during load/execution, since the class is final, and inlines the address. However, I'm not an expert on this matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment