admin管理员组

文章数量:1122846

Groovy 2.5.18 (this is custom extension code for an externally-developed project/product, so I have no control over versions). (This is using JUnit 4.13.2 and Java 17.0.13.)

The output of a failing test run is included in a comment towards the bottom of the code.

My goal is to create a base class with a setProperty method to intercept attempts to set properties and set a boolean field dirty to indicate that data needs to be synchronized/pushed. This works with an instance of the base class, captured in setPropertyWithoutInheritance. However, if I extend the base class with another class it fails with the error groovy.lang.MissingFieldException: No such field: myField for class: tests.Foo (I have included all of the output in a comment starting on line 54.). Using the direct access operator with this.@"$name" to actually set the field is exactly what the Groovy docs suggest to set the field within setProperty.

If I redeclare the myField field in the subclass, both test cases pass. (Ultimately I want my base class also to have several fields which will be common to the few subclasses to represent several variations of things; having to redeclare all of the common fields in the subclasses takes away some of the benefit of having the base in the first case.)

Eventually I found an [answer][1] to another question which might be the heart of the problem and my ignorance of Java/Groovy: "There is no field inheritance in Groovy nor in Java."


//package tests

import org.junit.Test
import org.junit.runner.JUnitCore


class scratch2 {

    @Test
    void setPropertyWithoutInheritance() {
        Bar b = new Bar()
        assert !b.dirty
        b.myField = "wow"
        assert b.dirty
        assert b.myField == "wow"

    }

    @Test
    void setPropertyWithInheritance() {
        Foo f = new Foo()
        assert !f.dirty
        f.myField = "howdy"
        assert f.myField == "howdy"
        assert f.dirty

    }
    static void main(String... args) {
        JUnitCore.main(new Object(){}.getClass().getEnclosingClass().getName())
    }
}

class Bar {
    String myField
    boolean dirty = false

    Bar() {
    }

    void setProperty(String name, Object value) {
        println("Called setProperty for ${name} = value '${value}'")
        if (name != "dirty") {
            this.@"$name" = value
        }
        this.@dirty = true
    }

}

class Foo extends Bar {

    // Uncomment below redeclaration of "myField" in subclass and tests pass
    /* Otherwise, Groovy 2.5.18 fails with the following output:
JUnit version 4.13.2
.Called setProperty for myField = value 'wow'
.Called setProperty for myField = value 'howdy'
E
Time: 0.083
There was 1 failure:
1) setPropertyWithInheritance(tests.scratch)
groovy.lang.MissingFieldException: No such field: myField for class: tests.Foo
    at groovy.lang.MetaClassImpl.setAttribute(MetaClassImpl.java:2915)
    at groovy.lang.MetaClassImpl.setAttribute(MetaClassImpl.java:3832)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.setGroovyObjectField(ScriptBytecodeAdapter.java:398)
    at tests.Bar.setProperty(scratch2.groovy:44)
    at org.codehaus.groovy.runtime.InvokerHelper.setProperty(InvokerHelper.java:213)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.setProperty(ScriptBytecodeAdapter.java:496)
    at tests.scratch.setPropertyWithInheritance(scratch2.groovy:24)

FAILURES!!!
Tests run: 2,  Failures: 1

     */
//    String myField

    Foo() {
        super()
    }

}


  [1]: 

本文标签: propertiesGroovy Fields with inheritance in setPropertyStack Overflow