Index: src/main/groovy/lang/ExpandoMetaClass.java =================================================================== --- src/main/groovy/lang/ExpandoMetaClass.java (revision 19479) +++ src/main/groovy/lang/ExpandoMetaClass.java (working copy) @@ -1117,16 +1117,24 @@ return super.createPogoCallCurrentSite(site, sender, args); } - public CallSite createConstructorSite(CallSite site, Object[] args) { + public CallSite createConstructorSite(CallSite site, Object[] args, Class type) { Class[] params = MetaClassHelper.convertToTypeArray(args); MetaMethod method = pickMethod(GROOVY_CONSTRUCTOR, params); + if(method!=null && method.getParameterTypes().length == args.length) { - return new ConstructorMetaMethodSite(site, this, method, params); + boolean typeMatches = (type == null) || (method.getDeclaringClass().getTheClass().equals(type)); + if(typeMatches) { + return new ConstructorMetaMethodSite(site, this, method, params); + } } - return super.createConstructorSite(site, args); + return super.createConstructorSite(site, args, type); } + public CallSite createConstructorSite(CallSite site, Object[] args) { + return createConstructorSite(site, args, null); // back-ward compatibility as it's a public method + } + private class SubClassDefiningClosure extends GroovyObjectSupport { private final Class klazz; Index: src/main/groovy/lang/MetaClassImpl.java =================================================================== --- src/main/groovy/lang/MetaClassImpl.java (revision 19464) +++ src/main/groovy/lang/MetaClassImpl.java (working copy) @@ -3027,7 +3027,7 @@ return new PogoMetaClassSite(site, this); } - public CallSite createConstructorSite(CallSite site, Object[] args) { + public CallSite createConstructorSite(CallSite site, Object[] args, Class type) { if (!(this instanceof AdaptingMetaClass)) { Class[] params = MetaClassHelper.convertToTypeArray(args); CachedConstructor constructor = (CachedConstructor) chooseMethod("", constructors, params); @@ -3046,6 +3046,10 @@ return new MetaClassConstructorSite(site, this); } + public CallSite createConstructorSite(CallSite site, Object[] args) { + return createConstructorSite(site, args, null); + } + public ClassInfo getClassInfo() { return theCachedClass.classInfo; } Index: src/main/org/codehaus/groovy/runtime/callsite/CallSiteArray.java =================================================================== --- src/main/org/codehaus/groovy/runtime/callsite/CallSiteArray.java (revision 19464) +++ src/main/org/codehaus/groovy/runtime/callsite/CallSiteArray.java (working copy) @@ -70,7 +70,7 @@ CallSite site; if (metaClass instanceof MetaClassImpl) { - site = ((MetaClassImpl)metaClass).createConstructorSite(callSite, args); + site = ((MetaClassImpl)metaClass).createConstructorSite(callSite, args, receiver); } else site = new MetaClassConstructorSite(callSite, metaClass); Index: src/test/groovy/bugs/Groovy4069Bug.groovy =================================================================== --- src/test/groovy/bugs/Groovy4069Bug.groovy (revision 0) +++ src/test/groovy/bugs/Groovy4069Bug.groovy (revision 0) @@ -0,0 +1,116 @@ +package groovy.bugs + +class Groovy4069Bug extends GroovyTestCase { + + void testEMCConstructorWithSubClassingTest1V1() { + def shell = new GroovyShell() + shell.evaluate """ + ExpandoMetaClass.enableGlobally() + try { + // ChildX.metaClass + def oldMetaClass = ParentX.metaClass + + def emc = new ExpandoMetaClass(ParentX, true, true) + emc.initialize() + GroovySystem.metaClassRegistry.setMetaClass(ParentX, emc) + + emc.constructor = { Map m -> ParentX.newInstance() } + + assert new ChildX([:]).class.name == 'ChildX' + + GroovySystem.metaClassRegistry.removeMetaClass(ParentX) + GroovySystem.metaClassRegistry.setMetaClass(ParentX, oldMetaClass) + + assert new ChildX([:]).class.name == 'ChildX' + } finally { + ExpandoMetaClass.disableGlobally() + } + class ParentX { def a } + class ChildX extends ParentX { def b } + """ + } + + void testEMCConstructorWithSubClassingTest1V2() { + def shell = new GroovyShell() + shell.evaluate """ + ExpandoMetaClass.enableGlobally() + try { + ChildX.metaClass + def oldMetaClass = ParentX.metaClass + + def emc = new ExpandoMetaClass(ParentX, true, true) + emc.initialize() + GroovySystem.metaClassRegistry.setMetaClass(ParentX, emc) + + emc.constructor = { Map m -> ParentX.newInstance() } + + assert new ChildX([:]).class.name == 'ChildX' + + GroovySystem.metaClassRegistry.removeMetaClass(ParentX) + GroovySystem.metaClassRegistry.setMetaClass(ParentX, oldMetaClass) + + assert new ChildX([:]).class.name == 'ChildX' + } finally { + ExpandoMetaClass.disableGlobally() + } + class ParentX { def a } + class ChildX extends ParentX { def b } + """ + } + + void testEMCConstructorWithSubClassingTest2V1() { + def shell = new GroovyShell() + shell.evaluate """ + ExpandoMetaClass.enableGlobally() + try { + // ChildY.metaClass + def oldMetaClass = ChildY.metaClass + + def emc = new ExpandoMetaClass(ChildY, true, true) + emc.initialize() + GroovySystem.metaClassRegistry.setMetaClass(ChildY, emc) + + emc.constructor = { Map m -> ParentY.newInstance() } + + assert new ChildY([:]).class.name == 'ParentY' + + GroovySystem.metaClassRegistry.removeMetaClass(ChildY) + GroovySystem.metaClassRegistry.setMetaClass(ChildY, oldMetaClass) + + assert new ChildY([:]).class.name == 'ChildY' + } finally { + ExpandoMetaClass.disableGlobally() + } + class ParentY { def a } + class ChildY extends ParentY { def b } + """ + } + + void testEMCConstructorWithSubClassingTest2V2() { + def shell = new GroovyShell() + shell.evaluate """ + ExpandoMetaClass.enableGlobally() + try { + ChildY.metaClass + def oldMetaClass = ChildY.metaClass + + def emc = new ExpandoMetaClass(ChildY, true, true) + emc.initialize() + GroovySystem.metaClassRegistry.setMetaClass(ChildY, emc) + + emc.constructor = { Map m -> ParentY.newInstance() } + + assert new ChildY([:]).class.name == 'ParentY' + + GroovySystem.metaClassRegistry.removeMetaClass(ChildY) + GroovySystem.metaClassRegistry.setMetaClass(ChildY, oldMetaClass) + + assert new ChildY([:]).class.name == 'ChildY' + } finally { + ExpandoMetaClass.disableGlobally() + } + class ParentY { def a } + class ChildY extends ParentY { def b } + """ + } +}