diff --git a/src/main/java/org/mvel2/ParserConfiguration.java b/src/main/java/org/mvel2/ParserConfiguration.java index 7267d79c2..37797a6bb 100644 --- a/src/main/java/org/mvel2/ParserConfiguration.java +++ b/src/main/java/org/mvel2/ParserConfiguration.java @@ -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. @@ -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)); } } @@ -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) { diff --git a/src/main/java/org/mvel2/optimizers/AbstractOptimizer.java b/src/main/java/org/mvel2/optimizers/AbstractOptimizer.java index 7e6a9d099..a7ec8b68c 100644 --- a/src/main/java/org/mvel2/optimizers/AbstractOptimizer.java +++ b/src/main/java/org/mvel2/optimizers/AbstractOptimizer.java @@ -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; } @@ -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; diff --git a/src/main/java/org/mvel2/util/ParseTools.java b/src/main/java/org/mvel2/util/ParseTools.java index f3c295798..8a11b0394 100644 --- a/src/main/java/org/mvel2/util/ParseTools.java +++ b/src/main/java/org/mvel2/util/ParseTools.java @@ -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; @@ -502,7 +501,7 @@ public static Class createClass(String className, ParserContext pCtx) throws Cla } WeakReference ref; - Class cls = null; + Class cls; if ((ref = cache.get(className)) != null && (cls = ref.get()) != null) { return cls; @@ -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; + } } diff --git a/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java b/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java index 602287496..fc6741b75 100644 --- a/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java +++ b/src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java @@ -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)); + } } \ No newline at end of file