diff --git a/subprojects/groovy-jmx/src/main/groovy/groovy/jmx/builder/JmxMetaMapBuilder.groovy b/subprojects/groovy-jmx/src/main/groovy/groovy/jmx/builder/JmxMetaMapBuilder.groovy index b341310d7b7..a11c2ba8ca0 100644 --- a/subprojects/groovy-jmx/src/main/groovy/groovy/jmx/builder/JmxMetaMapBuilder.groovy +++ b/subprojects/groovy-jmx/src/main/groovy/groovy/jmx/builder/JmxMetaMapBuilder.groovy @@ -389,6 +389,11 @@ class JmxMetaMapBuilder { * **************************************/ /** * Returns a meta map of operations from given object. + *
+ * Every public method reachable on the object is exported, inherited ones included, less + * the names in {@code OPS_EXCEPTION_LIST}. To export a narrower set, name the wanted + * operations explicitly in a descriptor rather than relying on this default. + * * @param object to profile * @return The meta map generated. */ @@ -396,11 +401,8 @@ class JmxMetaMapBuilder { def methods = object.metaClass.methods def ops = [:] - def declaredMethods = object.class.declaredMethods*.name - methods.each { method -> - // avoid picking up extra methods from parents - if ((declaredMethods.contains(method.name) && !OPS_EXCEPTION_LIST.contains(method.name)) || (!OPS_EXCEPTION_LIST.contains(method.name))) { + if (!OPS_EXCEPTION_LIST.contains(method.name)) { String mName = method.name MetaProperty prop = (mName.length() > 3 && (mName.startsWith("get") || mName.startsWith("set")) || diff --git a/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxMetaMapBuilderTest.groovy b/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxMetaMapBuilderTest.groovy index b44c0c3b7d0..97b78e53769 100644 --- a/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxMetaMapBuilderTest.groovy +++ b/subprojects/groovy-jmx/src/test/groovy/groovy/jmx/builder/JmxMetaMapBuilderTest.groovy @@ -340,6 +340,31 @@ class JmxMetaMapBuilderTest { assert map."set".name == "set" } + @Test + void testMetaClassAccessorsAreNotExportedAsOperations() { + // Not exported because getMetaClass/setMetaClass resolve to the metaClass MetaProperty + // and are dropped by the getter/setter filter, not because they are named in + // OPS_EXCEPTION_LIST. Pinned so that a change to that filter cannot quietly publish + // them as remotely invokable operations. + [new MockManagedObject(), new MockManagedGroovyObject()].each { object -> + def map = JmxMetaMapBuilder.buildOperationMapFrom(object) + assert !map."getMetaClass" + assert !map."setMetaClass" + } + } + + @Test + void testInheritedOperationsRemainExported() { + // The default export deliberately spans the whole inheritance chain: JmxBuilder's own + // embedded-descriptor fixtures declare their operations on a base class, and + // 'operations: "*"' routes here and must mean all of them. + def map = JmxMetaMapBuilder.buildOperationMapFrom(new EmbeddedAllOps()) + + assert map."doNothing" + assert map."doTwoThings" + assert map."doThreeThings" + } + @Test void testBuildOperationFromDescriptorMap() { def object = new MockManagedObject()