Skip to content

Commit

Permalink
Fix #188 - allow for module visibility when accessing class methods
Browse files Browse the repository at this point in the history
Implementing class may not be accessible but the interface it implements
is. In this case, need to make sure access is via the interface method.
  • Loading branch information
markt-asf committed Jun 20, 2022
1 parent bb1a058 commit de32480
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 23 deletions.
32 changes: 19 additions & 13 deletions api/src/main/java/jakarta/el/BeanELResolver.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021 Oracle and/or its affiliates and others.
* Copyright (c) 1997, 2022 Oracle and/or its affiliates and others.
* All rights reserved.
* Copyright 2004 The Apache Software Foundation
*
Expand Down Expand Up @@ -146,29 +146,35 @@ public BeanProperties get(Object key) {
*/
final static class BeanProperty {

final private Class<?> baseClass;
final private PropertyDescriptor descriptor;
private Method readMethod;
private Method writeMethod;
private PropertyDescriptor descriptor;

public BeanProperty(Class<?> baseClass, PropertyDescriptor descriptor) {
this.baseClass = baseClass;
this.descriptor = descriptor;
readMethod = ELUtil.getMethod(baseClass, descriptor.getReadMethod());
writeMethod = ELUtil.getMethod(baseClass, descriptor.getWriteMethod());
}

public Class<?> getPropertyType() {
return descriptor.getPropertyType();
}

public boolean isReadOnly() {
return getWriteMethod() == null;
public boolean isReadOnly(Object base) {
return getWriteMethod(base) == null;
}

public Method getReadMethod() {
public Method getReadMethod(Object base) {
if (readMethod == null) {
readMethod = ELUtil.getMethod(baseClass, base, descriptor.getReadMethod());
}
return readMethod;
}

public Method getWriteMethod() {
public Method getWriteMethod(Object base) {
if (writeMethod == null) {
writeMethod = ELUtil.getMethod(baseClass, base, descriptor.getWriteMethod());
}
return writeMethod;
}
}
Expand Down Expand Up @@ -285,7 +291,7 @@ public Class<?> getType(ELContext context, Object base, Object property) {
BeanProperty beanProperty = getBeanProperty(context, base, property);
context.setPropertyResolved(true);

if (isReadOnly || beanProperty.isReadOnly()) {
if (isReadOnly || beanProperty.isReadOnly(base)) {
return null;
}

Expand Down Expand Up @@ -329,7 +335,7 @@ public Object getValue(ELContext context, Object base, Object property) {
return null;
}

Method method = getBeanProperty(context, base, property).getReadMethod();
Method method = getBeanProperty(context, base, property).getReadMethod(base);
if (method == null) {
throw new PropertyNotFoundException(
getExceptionMessageString(context, "propertyNotReadable", new Object[] { base.getClass().getName(), property.toString() }));
Expand Down Expand Up @@ -397,7 +403,7 @@ public void setValue(ELContext context, Object base, Object property, Object val
throw new PropertyNotWritableException(getExceptionMessageString(context, "resolverNotwritable", new Object[] { base.getClass().getName() }));
}

Method method = getBeanProperty(context, base, property).getWriteMethod();
Method method = getBeanProperty(context, base, property).getWriteMethod(base);
if (method == null) {
throw new PropertyNotWritableException(
getExceptionMessageString(context, "propertyNotWritable", new Object[] { base.getClass().getName(), property.toString() }));
Expand Down Expand Up @@ -468,7 +474,7 @@ public Object invoke(ELContext context, Object base, Object methodName, Class<?>
return null;
}

Method method = ELUtil.findMethod(base.getClass(), methodName.toString(), paramTypes, params, false);
Method method = ELUtil.findMethod(base.getClass(), base, methodName.toString(), paramTypes, params, false);

for (Object param : params) {
// If the parameters is a LambdaExpression, set the ELContext
Expand Down Expand Up @@ -529,7 +535,7 @@ public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}

return getBeanProperty(context, base, property).isReadOnly();
return getBeanProperty(context, base, property).isReadOnly(base);
}

/**
Expand Down
31 changes: 23 additions & 8 deletions api/src/main/java/jakarta/el/ELUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package jakarta.el;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -198,8 +199,8 @@ static Object invokeConstructor(ELContext context, Constructor<?> constructor, O
}
}

static Method findMethod(Class<?> klass, String methodName, Class<?>[] paramTypes, Object[] params, boolean staticOnly) {
Method method = findMethod(klass, methodName, paramTypes, params);
static Method findMethod(Class<?> klass, Object base, String methodName, Class<?>[] paramTypes, Object[] params, boolean staticOnly) {
Method method = findMethod(klass, base, methodName, paramTypes, params);
if (staticOnly && !Modifier.isStatic(method.getModifiers())) {
throw new MethodNotFoundException("Method " + methodName + "for class " + klass + " not found or accessible");
}
Expand All @@ -221,7 +222,7 @@ static Object invokeMethod(ELContext context, Method method, Object base, Object
}
}

static Method findMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes, Object[] paramValues) {
static Method findMethod(Class<?> clazz, Object base, String methodName, Class<?>[] paramTypes, Object[] paramValues) {
if (clazz == null || methodName == null) {
throw new MethodNotFoundException("Method not found: " + clazz + "." + methodName + "(" + paramString(paramTypes) + ")");
}
Expand All @@ -240,7 +241,7 @@ static Method findMethod(Class<?> clazz, String methodName, Class<?>[] paramType
return null;
}

return getMethod(clazz, (Method) result.unWrap());
return getMethod(clazz, base, (Method) result.unWrap());
}

@SuppressWarnings("null")
Expand Down Expand Up @@ -557,16 +558,20 @@ private static Class<?>[] getTypesFromValues(Object[] values) {
* for a non-public class that implements a public interface, the read/write methods will be for the class, and
* therefore inaccessible. To correct this, a version of the same method must be found in a superclass or interface.
*/
static Method getMethod(Class<?> type, Method m) {
if (m == null || Modifier.isPublic(type.getModifiers())) {
static Method getMethod(Class<?> type, Object base, Method m) {
// If base is null, method MUST be static
// If base is non-null, method may be static or non-static
if (m == null ||
(Modifier.isPublic(type.getModifiers()) &&
(canAccess(base, m) || base != null && canAccess(null, m)))) {
return m;
}
Class<?>[] inf = type.getInterfaces();
Method mp = null;
for (int i = 0; i < inf.length; i++) {
try {
mp = inf[i].getMethod(m.getName(), m.getParameterTypes());
mp = getMethod(mp.getDeclaringClass(), mp);
mp = getMethod(mp.getDeclaringClass(), base, mp);
if (mp != null) {
return mp;
}
Expand All @@ -578,7 +583,7 @@ static Method getMethod(Class<?> type, Method m) {
if (sup != null) {
try {
mp = sup.getMethod(m.getName(), m.getParameterTypes());
mp = getMethod(mp.getDeclaringClass(), mp);
mp = getMethod(mp.getDeclaringClass(), base, mp);
if (mp != null) {
return mp;
}
Expand Down Expand Up @@ -609,6 +614,16 @@ static Constructor<?> getConstructor(Class<?> type, Constructor<?> c) {
return null;
}


static boolean canAccess(Object base, AccessibleObject accessibleObject) {
try {
return accessibleObject.canAccess(base);
} catch (IllegalArgumentException iae) {
return false;
}
}


@SuppressWarnings("null") // params cannot be null when used
static Object[] buildParameters(ELContext context, Class<?>[] parameterTypes, boolean isVarArgs, Object[] params) {
Object[] parameters = null;
Expand Down
4 changes: 2 additions & 2 deletions api/src/main/java/jakarta/el/StaticFieldELResolver.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021 Oracle and/or its affiliates and others.
* Copyright (c) 2012, 2022 Oracle and/or its affiliates and others.
* All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -171,7 +171,7 @@ public Object invoke(ELContext context, Object base, Object methodName, Class<?>
Constructor<?> constructor = ELUtil.findConstructor(klass, paramTypes, params);
ret = ELUtil.invokeConstructor(context, constructor, params);
} else {
Method method = ELUtil.findMethod(klass, name, paramTypes, params, true);
Method method = ELUtil.findMethod(klass, base, name, paramTypes, params, true);
ret = ELUtil.invokeMethod(context, method, null, params);
}
context.setPropertyResolved(base, methodName);
Expand Down

0 comments on commit de32480

Please sign in to comment.