Skip to content

Commit

Permalink
propagate sender class for getProperty and setProperty
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Apr 28, 2024
1 parent 8324f8b commit c880517
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 56 deletions.
31 changes: 15 additions & 16 deletions src/main/java/groovy/lang/MetaClassImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -1820,7 +1820,7 @@ public Object getProperty(final Class sender, final Object object, final String
//----------------------------------------------------------------------
// getter
//----------------------------------------------------------------------
Tuple2<MetaMethod, MetaProperty> methodAndProperty = createMetaMethodAndMetaProperty(sender, sender, name, useSuper, isStatic);
Tuple2<MetaMethod, MetaProperty> methodAndProperty = createMetaMethodAndMetaProperty(sender, name, useSuper, isStatic);
MetaMethod method = methodAndProperty.getV1();
MetaProperty prop = methodAndProperty.getV2();

Expand Down Expand Up @@ -1861,10 +1861,10 @@ public Object getProperty(final Class sender, final Object object, final String
Object[] arguments = EMPTY_ARGUMENTS;
if (method == null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
// check for propertyMissing provided through a category; TODO:should this have lower precedence?
method = getCategoryMethodGetter(sender, PROPERTY_MISSING, true);
method = getCategoryMethodGetter(theClass, PROPERTY_MISSING, true);
if (method == null) {
// check for a generic get method provided through a category
method = getCategoryMethodGetter(sender, "get", true);
method = getCategoryMethodGetter(theClass, "get", true);
}
if (method != null) arguments = new Object[]{name};
}
Expand Down Expand Up @@ -1935,7 +1935,7 @@ public void setProperty(Object object, Object newValue) {
//----------------------------------------------------------------------
// getter
//----------------------------------------------------------------------
Tuple2<MetaMethod, MetaProperty> methodAndProperty = createMetaMethodAndMetaProperty(sender, theClass, name, useSuper, isStatic);
Tuple2<MetaMethod, MetaProperty> methodAndProperty = createMetaMethodAndMetaProperty(sender, name, useSuper, isStatic);
MetaMethod method = methodAndProperty.getV1();
MetaProperty prop = methodAndProperty.getV2();

Expand Down Expand Up @@ -1980,9 +1980,9 @@ public void setProperty(Object object, Object newValue) {
// generic get method
//----------------------------------------------------------------------
if (!useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
method = getCategoryMethodGetter(sender, "get", true);
method = getCategoryMethodGetter(theClass, "get", true);
if (null == method) {
method = getCategoryMethodGetter(sender, PROPERTY_MISSING, true);
method = getCategoryMethodGetter(theClass, PROPERTY_MISSING, true);
}
if (method != null) {
return new GetMethodMetaProperty(name, VM_PLUGIN.transformMetaMethod(this, method));
Expand Down Expand Up @@ -2101,13 +2101,13 @@ private boolean isVisibleProperty(final MetaProperty field, final MetaMethod met
return !owner.isAssignableFrom(method.getDeclaringClass().getTheClass()) && !method.getDeclaringClass().isInterface();
}

private Tuple2<MetaMethod, MetaProperty> createMetaMethodAndMetaProperty(final Class senderForMP, final Class senderForCMG, final String name, final boolean useSuper, final boolean isStatic) {
private Tuple2<MetaMethod, MetaProperty> createMetaMethodAndMetaProperty(final Class sender, final String name, final boolean useSuper, final boolean isStatic) {
MetaMethod method = null;
MetaProperty mp = getMetaProperty(senderForMP, name, useSuper, isStatic);
MetaProperty mp = getMetaProperty(sender, name, useSuper, isStatic);
if ((mp == null || mp instanceof CachedField) && !name.isEmpty() && isUpperCase(name.charAt(0)) && (name.length() < 2 || !isUpperCase(name.charAt(1))) && !"Class".equals(name) && !"MetaClass".equals(name)) {
// GROOVY-9618 adjust because capitalised properties aren't stored as meta bean props
MetaProperty saved = mp;
mp = getMetaProperty(senderForMP, BeanUtils.decapitalize(name), useSuper, isStatic);
mp = getMetaProperty(sender, BeanUtils.decapitalize(name), useSuper, isStatic);
if (mp == null || (saved != null && mp instanceof CachedField)) {
// restore if we didn't find something better
mp = saved;
Expand All @@ -2124,7 +2124,7 @@ private Tuple2<MetaMethod, MetaProperty> createMetaMethodAndMetaProperty(final C
if (!useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
String getterName = GroovyCategorySupport.getPropertyCategoryGetterName(name);
if (getterName != null) {
MetaMethod categoryMethod = getCategoryMethodGetter(senderForCMG, getterName, false);
MetaMethod categoryMethod = getCategoryMethodGetter(theClass, getterName, false);
if (categoryMethod != null)
method = categoryMethod;
}
Expand Down Expand Up @@ -2721,11 +2721,10 @@ public void setProperty(final Class sender, final Object object, final String na
}

// check for a category method named like a setter
if (!useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()
&& name.length() > 0) {
String getterName = GroovyCategorySupport.getPropertyCategorySetterName(name);
if (getterName != null) {
MetaMethod categoryMethod = getCategoryMethodSetter(sender, getterName, false);
if (!useSuper && !isStatic && !name.isEmpty() && GroovyCategorySupport.hasCategoryInCurrentThread()) {
var setterName = GroovyCategorySupport.getPropertyCategorySetterName(name);
if (setterName != null) {
MetaMethod categoryMethod = getCategoryMethodSetter(theClass, setterName, false);
if (categoryMethod != null) {
method = categoryMethod;
arguments = new Object[]{newValue};
Expand Down Expand Up @@ -2778,7 +2777,7 @@ public void setProperty(final Class sender, final Object object, final String na
//----------------------------------------------------------------------
// check for a generic get method provided through a category
if (method == null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
method = getCategoryMethodSetter(sender, "set", true);
method = getCategoryMethodSetter(theClass, "set", true);
if (method != null) arguments = new Object[]{name, newValue};
}
if (method == null && genericSetMethod != null && (genericSetMethod.isStatic() || !isStatic)) {
Expand Down
52 changes: 37 additions & 15 deletions src/main/java/groovy/util/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -294,42 +294,65 @@ private static List<Node> buildChildrenFromClosure(Closure c) {
* @param metaClass the original metaclass
* @param nodeClass the class whose metaclass we wish to override (this class or a subclass)
*/
protected static void setMetaClass(final MetaClass metaClass, Class nodeClass) {
protected static void setMetaClass(final MetaClass metaClass, final Class nodeClass) {
// TODO Is protected static a bit of a smell?
// TODO perhaps set nodeClass to be Class<? extends Node>
final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
GroovySystem.getMetaClassRegistry().setMetaClass(nodeClass, new DelegatingMetaClass(metaClass) {

@Override
public Object getAttribute(final Object object, final String attribute) {
Node n = (Node) object;
return n.get("@" + attribute);
return ((Node) object).get("@" + attribute);
}

@Override
public Object getAttribute(final Class sender, final Object object, final String attribute, final boolean isSuper) {
return getAttribute(object, attribute);
}

@Override
public void setAttribute(final Object object, final String attribute, final Object newValue) {
Node n = (Node) object;
n.attributes().put(attribute, newValue);
((Node) object).attributes().put(attribute, newValue);
}

@Override
public void setAttribute(final Class sender, final Object object, final String attribute, final Object newValue, final boolean isSuper, final boolean isInner) {
setAttribute(object, attribute, newValue);
}

@Override
public Object getProperty(Object object, String property) {
public Object getProperty(final Object object, final String property) {
if (object instanceof Node) {
Node n = (Node) object;
return n.get(property);
return ((Node) object).get(property);
}
return super.getProperty(object, property);
}

@Override
public void setProperty(Object object, String property, Object newValue) {
public Object getProperty(final Class sender, final Object object, final String property, final boolean isSuper, final boolean isInner) {
if (object instanceof Node) {
return ((Node) object).get(property);
}
return super.getProperty(sender, object, property, isSuper, isInner);
}

@Override
public void setProperty(final Object object, final String property, final Object newValue) {
if (property.startsWith("@")) {
setAttribute(object, property.substring(1), newValue);
return;
} else {
super.setProperty(object, property, newValue);
}
delegate.setProperty(object, property, newValue);
}

};
GroovySystem.getMetaClassRegistry().setMetaClass(nodeClass, newMetaClass);
@Override
public void setProperty(final Class sender, final Object object, final String property, final Object newValue, final boolean isSuper, final boolean isInner) {
if (property.startsWith("@")) {
setAttribute(object, property.substring(1), newValue);
} else {
super.setProperty(sender, object, property, newValue, isSuper, isInner);
}
}
});
}

/**
Expand Down Expand Up @@ -786,7 +809,6 @@ public void print(PrintWriter out) {
new NodePrinter(out).print(this);
}


/**
* Converts the text of this GPathResult to an Integer object.
*
Expand Down
50 changes: 31 additions & 19 deletions src/main/java/groovy/util/NodeList.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
* A List implementation which is returned by queries on a {@link Node}
Expand Down Expand Up @@ -74,38 +72,53 @@ public Object clone() {
return result;
}

protected static void setMetaClass(final Class nodelistClass, final MetaClass metaClass) {
final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
protected static void setMetaClass(final Class nodeListClass, final MetaClass metaClass) {
GroovySystem.getMetaClassRegistry().setMetaClass(nodeListClass, new DelegatingMetaClass(metaClass) {

@Override
public Object getAttribute(final Object object, final String attribute) {
NodeList nl = (NodeList) object;
Iterator it = nl.iterator();
List result = new ArrayList();
while (it.hasNext()) {
Node node = (Node) it.next();
result.add(node.attributes().get(attribute));
NodeList list = (NodeList) object;
var result = new ArrayList<Object>(list.size());
for (Object node : list) {
var attributes = ((Node) node).attributes();
result.add(attributes.get(attribute));
}
return result;
}

@Override
public Object getAttribute(Class sender, Object object, String attribute, boolean isSuper) {
return getAttribute(object, attribute);
}

@Override
public void setAttribute(final Object object, final String attribute, final Object newValue) {
for (Object o : (NodeList) object) {
Node node = (Node) o;
node.attributes().put(attribute, newValue);
for (Object node : (NodeList) object) {
((Node) node).attributes().put(attribute, newValue);
}
}

@Override
public Object getProperty(Object object, String property) {
public void setAttribute(final Class sender, final Object object, final String attribute, final Object newValue, final boolean isSuper, final boolean isInner) {
setAttribute(object, attribute, newValue);
}

@Override
public Object getProperty(final Object object, final String property) {
if (object instanceof NodeList) {
NodeList nl = (NodeList) object;
return nl.getAt(property);
return ((NodeList) object).getAt(property);
}
return super.getProperty(object, property);
}
};
GroovySystem.getMetaClassRegistry().setMetaClass(nodelistClass, newMetaClass);

@Override
public Object getProperty(final Class sender, final Object object, final String property, final boolean isSuper, final boolean isInner) {
if (object instanceof NodeList) {
return ((NodeList) object).getAt(property);
}
return super.getProperty(sender, object, property, isSuper, isInner);
}
});
}

/**
Expand Down Expand Up @@ -197,5 +210,4 @@ public void plus(Closure c) {
((Node) o).plus(c);
}
}

}
4 changes: 2 additions & 2 deletions src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public static void setProperty(Object object, String property, Object newValue)
} else if (object instanceof Class) {
metaRegistry.getMetaClass((Class) object).setProperty(object, property, newValue);
} else {
((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object).setProperty(object, property, newValue);
((MetaClassRegistryImpl) metaRegistry).getMetaClass(object).setProperty(object, property, newValue);
}
}

Expand Down Expand Up @@ -586,7 +586,7 @@ public static MetaClass getMetaClass(Object object) {
} else if (object instanceof Class) {
return metaRegistry.getMetaClass((Class<?>) object); // GROOVY-10819
} else {
return ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object);
return ((MetaClassRegistryImpl) metaRegistry).getMetaClass(object);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import groovy.lang.GroovyInterceptable;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovySystem;
import groovy.lang.IntRange;
import groovy.lang.MetaClass;
import groovy.lang.MissingMethodException;
Expand Down Expand Up @@ -244,8 +243,8 @@ public static Object invokeNew0(Class senderClass, Class receiver) throws Throwa
// --------------------------------------------------------

public static int selectConstructorAndTransformArguments(Object[] arguments, int numberOfConstructors, Class which) throws Throwable {
MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(which);
try {
MetaClass metaClass = InvokerHelper.getMetaClass(which);
return metaClass.selectConstructorAndTransformArguments(numberOfConstructors, arguments);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
Expand Down Expand Up @@ -468,7 +467,13 @@ public static void setPropertyOnSuperSpreadSafe(Object messageArgument, Class se

public static Object getProperty(Class senderClass, Object receiver, String messageName) throws Throwable {
try {
return InvokerHelper.getProperty(receiver, messageName);
if (receiver instanceof GroovyObject) {
var groovyObject = (GroovyObject) receiver;
return groovyObject.getProperty(messageName);
} else {
MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
return metaClass.getProperty(senderClass, receiver, messageName, false, false);
}
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
Expand All @@ -494,7 +499,13 @@ public static Object getPropertySpreadSafe(Class senderClass, Object receiver, S

public static void setProperty(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
try {
InvokerHelper.setProperty(receiver, messageName, messageArgument);
if (receiver instanceof GroovyObject) {
var groovyObject = (GroovyObject) receiver;
groovyObject.setProperty(messageName, messageArgument);
} else {
MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
metaClass.setProperty(senderClass, receiver, messageName, messageArgument, false, false);
}
} catch (GroovyRuntimeException gre) {
if (gre instanceof MissingPropertyException
&& receiver instanceof GroovyObject
Expand Down

0 comments on commit c880517

Please sign in to comment.