Skip to content

Commit

Permalink
fix import resolution with inner classes
Browse files Browse the repository at this point in the history
  • Loading branch information
mariofusco committed Aug 3, 2015
1 parent dbab7f0 commit 6e568f1
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 30 deletions.
16 changes: 11 additions & 5 deletions src/main/java/org/mvel2/ParserConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static java.lang.Thread.currentThread;
import static org.mvel2.util.ParseTools.forNameWithInner;

/**
* The resusable parser configuration object.
Expand Down Expand Up @@ -118,7 +124,7 @@ private boolean addClassMemberStaticImports(String packageName) {
}
else {
for (Field f : c.getDeclaredFields()) {
if ((f.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) != 0) {
if ((f.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) == (Modifier.STATIC | Modifier.PUBLIC)) {
imports.put(f.getName(), f.get(null));
}
}
Expand Down Expand Up @@ -160,10 +166,10 @@ private boolean checkForDynamicImport(String className) {
Class cls = null;
for (String pkg : packageImports) {
try {
cls = Class.forName(pkg + "." + className, true, getClassLoader());
cls = forNameWithInner( pkg + "." + className, getClassLoader() );
found++;
}
catch (ClassNotFoundException e) {
catch (ClassNotFoundException cnfe) {
// do nothing.
}
catch (NoClassDefFoundError e) {
Expand Down
29 changes: 6 additions & 23 deletions src/main/java/org/mvel2/optimizers/AbstractOptimizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,21 @@ protected Object tryStaticAccess() {
case '.':
if (!meth) {
ClassLoader classLoader = pCtx != null ? pCtx.getClassLoader() : currentThread().getContextClassLoader();
String test = new String(expr, start, (cursor = last) - start);
try {
String test = new String(expr, start, (cursor = last) - start);
if (MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS && test.endsWith(".class"))
test = test.substring(0, test.length() - 6);

return Class.forName(test, true, classLoader);
}
catch (ClassNotFoundException e) {
} catch (ClassNotFoundException cnfe) {
try {
return findInnerClass( test, classLoader, cnfe );
} catch (ClassNotFoundException e) { /* ignore */ }
Class cls = forNameWithInner(new String(expr, start, i - start), classLoader);
String name = new String(expr, i + 1, end - i - 1);
try {
return cls.getField(name);
}
catch (NoSuchFieldException nfe) {
} catch (NoSuchFieldException nfe) {
for (Method m : cls.getMethods()) {
if (name.equals(m.getName())) return m;
}
Expand Down Expand Up @@ -160,24 +161,6 @@ protected Object tryStaticAccess() {
return null;
}

private Class forNameWithInner(String className, ClassLoader classLoader) throws ClassNotFoundException {
ClassNotFoundException cnfe = null;
try {
return Class.forName(className, true, classLoader);
} catch (ClassNotFoundException e) {
cnfe = e;
}

for (int lastDotPos = className.lastIndexOf('.'); lastDotPos > 0; lastDotPos = className.lastIndexOf('.')) {
className = className.substring(0, lastDotPos) + "$" + className.substring(lastDotPos+1);
try {
return Class.forName(className, true, classLoader);
} catch (ClassNotFoundException e) { }
}

throw cnfe;
}

protected int nextSubToken() {
skipWhitespace();
nullSafe = false;
Expand Down
21 changes: 19 additions & 2 deletions src/main/java/org/mvel2/util/ParseTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,6 @@ public static Method getWidenedTarget(Class cls, Method method) {

if (best != method) return best;

currentCls = cls;
for (currentCls = cls; currentCls != null; currentCls = currentCls.getSuperclass()) {
if ((m = getExactMatch(name, args, rt, currentCls)) != null) {
best = m;
Expand Down Expand Up @@ -502,7 +501,7 @@ public static Class createClass(String className, ParserContext pCtx) throws Cla
}

WeakReference<Class> ref;
Class cls = null;
Class cls;

if ((ref = cache.get(className)) != null && (cls = ref.get()) != null) {
return cls;
Expand Down Expand Up @@ -2184,4 +2183,22 @@ public static char[] readIn(InputStream inStream, String encoding) throws IOExce
if (inStream != null) inStream.close();
}
}

public static Class forNameWithInner(String className, ClassLoader classLoader) throws ClassNotFoundException {
try {
return Class.forName(className, true, classLoader);
} catch (ClassNotFoundException cnfe) {
return findInnerClass( className, classLoader, cnfe );
}
}

public static Class findInnerClass( String className, ClassLoader classLoader, ClassNotFoundException cnfe ) throws ClassNotFoundException {
for (int lastDotPos = className.lastIndexOf('.'); lastDotPos > 0; lastDotPos = className.lastIndexOf('.')) {
className = className.substring(0, lastDotPos) + "$" + className.substring(lastDotPos+1);
try {
return Class.forName(className, true, classLoader);
} catch (ClassNotFoundException e) { /* ignore */ }
}
throw cnfe;
}
}
36 changes: 36 additions & 0 deletions src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -4410,4 +4410,40 @@ public void testEmptyOperatorOnInteger() {
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("zero == empty", pctx), vars));
assertEquals(false, MVEL.executeExpression(MVEL.compileExpression("nonZero == empty", pctx), vars));
}

public void testInstanceofOnInnerClass() {
ParserConfiguration conf = new ParserConfiguration();
conf.addImport(ARef.class);
ParserContext pctx = new ParserContext( conf );
pctx.setStrictTypeEnforcement(true);
pctx.setStrongTyping(true);
pctx.addInput("value", Object.class);
Map vars = new HashMap() {{ put("value", new ARef()); }};
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof ARef", pctx), vars));
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof " + ARef.class.getCanonicalName(), pctx), vars));
}

public void testInstanceofWithPackageImport() {
ParserConfiguration conf = new ParserConfiguration();
conf.addPackageImport( "org.mvel2.tests.core" );
ParserContext pctx = new ParserContext( conf );
pctx.setStrictTypeEnforcement(true);
pctx.setStrongTyping(true);
pctx.addInput("value", Object.class);
Map vars = new HashMap() {{ put("value", new CoreConfidenceTests()); }};
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof CoreConfidenceTests", pctx), vars));
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof " + CoreConfidenceTests.class.getCanonicalName(), pctx), vars));
}

public void testInstanceofWithPackageImportAndInnerClass() {
ParserConfiguration conf = new ParserConfiguration();
conf.addPackageImport( "org.mvel2.tests.core.CoreConfidenceTests" );
ParserContext pctx = new ParserContext( conf );
pctx.setStrictTypeEnforcement(true);
pctx.setStrongTyping(true);
pctx.addInput("value", Object.class);
Map vars = new HashMap() {{ put("value", new ARef()); }};
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof ARef", pctx), vars));
assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof " + ARef.class.getCanonicalName(), pctx), vars));
}
}

0 comments on commit 6e568f1

Please sign in to comment.