diff --git a/src/main/java/ognl/ASTMethod.java b/src/main/java/ognl/ASTMethod.java index 30112549..ec0785ef 100644 --- a/src/main/java/ognl/ASTMethod.java +++ b/src/main/java/ognl/ASTMethod.java @@ -62,7 +62,7 @@ public ASTMethod(OgnlParser p, int id) super(p, id); } - /** + /** * Called from parser action. * * @param methodName the method name. @@ -74,7 +74,7 @@ public void setMethodName(String methodName) /** * Returns the method name that this node will call. - * + * * @return the method name. */ public String getMethodName() @@ -192,7 +192,7 @@ public String toGetSourceString(OgnlContext context, Object target) // TODO: This is a hacky workaround until javassist supports varargs method invocations - boolean varArgs = OgnlRuntime.isJdk15() && m.isVarArgs(); + boolean varArgs = m.isVarArgs(); if (varArgs) { @@ -353,7 +353,7 @@ public String toSetSourceString(OgnlContext context, Object target) _getterClass = wrapper; } - boolean varArgs = OgnlRuntime.isJdk15() && m.isVarArgs(); + boolean varArgs = m.isVarArgs(); if (varArgs) { diff --git a/src/main/java/ognl/ASTStaticField.java b/src/main/java/ognl/ASTStaticField.java index c4ba8701..b2a3ddea 100644 --- a/src/main/java/ognl/ASTStaticField.java +++ b/src/main/java/ognl/ASTStaticField.java @@ -84,7 +84,7 @@ public boolean isNodeConstant(OgnlContext context) if (fieldName.equals("class")) { result = true; - } else if (OgnlRuntime.isJdk15() && c.isEnum()) + } else if (c.isEnum()) { result = true; } else @@ -129,7 +129,7 @@ Class getFieldClass(OgnlContext context) if (fieldName.equals("class")) { return c; - } else if (OgnlRuntime.isJdk15() && c.isEnum()) + } else if (c.isEnum()) { return c; } else diff --git a/src/main/java/ognl/OgnlRuntime.java b/src/main/java/ognl/OgnlRuntime.java index 98379fd7..2b504882 100644 --- a/src/main/java/ognl/OgnlRuntime.java +++ b/src/main/java/ognl/OgnlRuntime.java @@ -641,27 +641,6 @@ public static void clearAdditionalCache() } } - /** - * Checks if the current jvm is java language >= 1.5 compatible. - * - * @return True if jdk15 features are present. - */ - public static boolean isJdk15() - { - if (_jdkChecked) - return _jdk15; - - try - { - Class.forName("java.lang.annotation.Annotation"); - _jdk15 = true; - } catch (Exception e) { /* ignore */ } - - _jdkChecked = true; - - return _jdk15; - } - /** * Get the Major Java Version detected by OGNL. * @@ -720,7 +699,7 @@ public static void compileExpression(OgnlContext context, Node expression, Objec * Gets the "target" class of an object for looking up accessors that are registered on the * target. If the object is a Class object this will return the Class itself, else it will * return object's getClass() result. - * + * * @param o the Object from which to retrieve its Class. * @return the Class of o. */ @@ -732,7 +711,7 @@ public static Class getTargetClass(Object o) /** * Returns the base name (the class name without the package name prepended) of the object * given. - * + * * @param o the Object from which to retrieve its base classname. * @return the base classname of o's Class. */ @@ -743,7 +722,7 @@ public static String getBaseName(Object o) /** * Returns the base name (the class name without the package name prepended) of the class given. - * + * * @param c the Class from which to retrieve its name. * @return the base classname of c. */ @@ -771,7 +750,7 @@ public static String getClassName(Class c, boolean fullyQualified) /** * Returns the package name of the object's class. - * + * * @param o the Object from which to retrieve its Class package name. * @return the package name of o's Class. */ @@ -782,7 +761,7 @@ public static String getPackageName(Object o) /** * Returns the package name of the class given. - * + * * @param c the Class from which to retrieve its package name. * @return the package name of c. */ @@ -796,7 +775,7 @@ public static String getClassPackageName(Class c) /** * Returns a "pointer" string in the usual format for these things - 0x<hex digits>. - * + * * @param num the int to convert into a "pointer" string in hex format. * @return the String representing num as a "pointer" string in hex format. */ @@ -824,7 +803,7 @@ public static String getPointerString(int num) /** * Returns a "pointer" string in the usual format for these things - 0x<hex digits> for the * object given. This will always return a unique value for each object. - * + * * @param o the Object to convert into a "pointer" string in hex format. * @return the String representing o as a "pointer" string in hex format. */ @@ -837,7 +816,7 @@ public static String getPointerString(Object o) * Returns a unique descriptor string that includes the object's class and a unique integer * identifier. If fullyQualified is true then the class name will be fully qualified to include * the package name, else it will be just the class' base name. - * + * * @param object the Object for which a unique descriptor string is desired. * @param fullyQualified true if the descriptor string is fully-qualified (package name), false for just the Class' base name. * @return the unique descriptor String for the object, qualified as per fullyQualified parameter. @@ -866,7 +845,7 @@ public static String getUniqueDescriptor(Object object, boolean fullyQualified) /** * Returns a unique descriptor string that includes the object's class' base name and a unique * integer identifier. - * + * * @param object the Object for which a unique descriptor string is desired. * @return the unique descriptor String for the object, NOT fully-qualified. */ @@ -879,7 +858,7 @@ public static String getUniqueDescriptor(Object object) * Utility to convert a List into an Object[] array. If the list is zero elements this will * return a constant array; toArray() on List always returns a new object and this is wasteful * for our purposes. - * + * * @param list the List to convert into an Object array. * @return the array of Objects from the list. */ @@ -901,7 +880,7 @@ public static Object[] toArray(List list) /** * Returns the parameter types of the given method. - * + * * @param m the Method whose parameter types are being queried. * @return the array of Class elements representing m's parameters. May be null if m does not utilize parameters. */ @@ -948,7 +927,7 @@ public static Class[] findParameterTypes(Class type, Method m) return types; } - if (type == null || !isJdk15()) + if (type == null) { return getParameterTypes(m); } @@ -1075,7 +1054,7 @@ static Class findType(Type[] types, Class type) /** * Returns the parameter types of the given method. - * + * * @param c the Constructor whose parameter types are being queried. * @return the array of Class elements representing c's parameters. May be null if c does not utilize parameters. */ @@ -1114,7 +1093,7 @@ public static void setSecurityManager(SecurityManager value) /** * Permission will be named "invoke.<declaring-class>.<method-name>". - * + * * @param method the Method whose Permission is being requested. * @return the Permission for method named "invoke.<declaring-class>.<method-name>". */ @@ -1357,7 +1336,7 @@ public static Class[] getArgClasses(Object[] args) { * given object can be passed as an argument to a method or constructor whose parameter type is * the given class. If object is null this will return true because null is compatible with any * type. - * + * * @param object the Object to check for type-compatibility with Class c. * @param c the Class for which object's type-compatibility is being checked. * @return true if object is type-compatible with c. @@ -1488,7 +1467,7 @@ public static boolean areArgsCompatible(Object[] args, Class[] classes) public static ArgsCompatbilityReport areArgsCompatible(Class[] args, Class[] classes, Method m) { - boolean varArgs = m != null && isJdk15() && m.isVarArgs(); + boolean varArgs = m != null && m.isVarArgs(); if ( args==null || args.length == 0 ) { // handle methods without arguments if ( classes == null || classes.length == 0 ) { @@ -1543,7 +1522,7 @@ public static ArgsCompatbilityReport areArgsCompatible(Class[] args, Class[] cla /** * Tells whether the first array of classes is more specific than the second. Assumes that the * two arrays are of the same length. - * + * * @param classes1 the Class array being checked to see if it is "more specific" than classes2. * @param classes2 the Class array that classes1 is being checked against to see if classes1 is "more specific" than classes2. * @return true if the classes1 Class contents are "more specific" than classes2 Class contents, false otherwise. @@ -1822,7 +1801,7 @@ private static MatchingMethod findBestMethod(List methods, Class typeClass, Stri } else { // two methods with same score - direct compare to find the better one... // legacy wins over varargs - if (isJdk15() && (m.isVarArgs() || mm.mMethod.isVarArgs())) { + if (m.isVarArgs() || mm.mMethod.isVarArgs()) { if (m.isVarArgs() && !mm.mMethod.isVarArgs()) { // keep with current } else if (!m.isVarArgs() && mm.mMethod.isVarArgs()) { @@ -1928,7 +1907,7 @@ public static Object callAppropriateMethod(OgnlContext context, Object source, O Object[] convertedArgs = actualArgs; - if (isJdk15() && method.isVarArgs()) + if (method.isVarArgs()) { Class[] parmTypes = method.getParameterTypes(); @@ -1960,13 +1939,17 @@ public static Object callAppropriateMethod(OgnlContext context, Object source, O } } - varArgs = varArgsList.toArray(); - } else - { + if (actualArgs.length == 1) { + varArgs = (Object[]) Array.newInstance(args[0].getClass(), 1); + } else { + varArgs = (Object[]) Array.newInstance(parmTypes[i].getComponentType(), varArgsList.size()); + } + System.arraycopy(varArgsList.toArray(), 0, varArgs, 0, varArgs.length); + } else { varArgs = new Object[0]; } // If this is the only parameter, explode the array - if (actualArgs.length == 1) { + if (actualArgs.length == 1 && args[0].getClass().isArray()) { convertedArgs = varArgs; } else { // there are more parameters, varargs is the last one convertedArgs[i] = varArgs; @@ -2109,7 +2092,7 @@ public static Object callConstructor(OgnlContext context, String className, Obje /** * Don't use this method as it doesn't check member access rights via {@link MemberAccess} interface - * + * * @param context the current execution context. * @param target the object to invoke the property name get on. * @param propertyName the name of the property to be retrieved from target. @@ -2130,7 +2113,7 @@ public static final Object getMethodValue(OgnlContext context, Object target, St * If the checkAccessAndExistence flag is true this method will check to see if the method * exists and if it is accessible according to the context's MemberAccess. If neither test * passes this will return NotFound. - * + * * @param context the current execution context. * @param target the object to invoke the property name get on. * @param propertyName the name of the property to be retrieved from target. @@ -2173,7 +2156,7 @@ public static final Object getMethodValue(OgnlContext context, Object target, St /** * Don't use this method as it doesn't check member access rights via {@link MemberAccess} interface - * + * * @param context the current execution context. * @param target the object to invoke the property name get on. * @param propertyName the name of the property to be set for target. @@ -2462,7 +2445,7 @@ public static Field getField(Class inClass, String name) /** * Don't use this method as it doesn't check member access rights via {@link MemberAccess} interface - * + * * @param context the current execution context. * @param target the object to invoke the property name get on. * @param propertyName the name of the property to be set for target. @@ -2569,7 +2552,7 @@ public static boolean hasField(OgnlContext context, Object target, Class inClass * @param context The current ognl context * @param className The name of the class which contains the field * @param fieldName The name of the field whose value should be returned - * + * * @return The value of the (static) fieldName * @throws OgnlException for lots of different reasons. */ @@ -2591,7 +2574,7 @@ public static Object getStaticField(OgnlContext context, String className, Strin if (fieldName.equals("class")) { return c; - } else if (OgnlRuntime.isJdk15() && c.isEnum()) + } else if (c.isEnum()) { try { return Enum.valueOf(c, fieldName); @@ -2744,11 +2727,11 @@ private static void addIfAccessor(List result, Method method, String baseName, b * Convenience used to check if a method is a synthetic method so as to avoid * calling un-callable methods. These methods are not considered callable by * OGNL in almost all circumstances. - * + * * This method considers any synthetic method (even bridge methods) as being un-callable. * Even though synthetic and bridge methods can technically be called, by default * OGNL excludes them from consideration. - * + * * Synthetic methods should be excluded in general, since calling such methods * could introduce unanticipated risks. * @@ -2763,19 +2746,19 @@ static boolean isMethodCallable(Method m) /** * Convenience used to check if a method is either a non-synthetic method or * a bridge method. - * - * Warning: This method should NOT be used as a direct replacement for + * + * Warning: This method should NOT be used as a direct replacement for * {@link #isMethodCallable(Method)}. Almost all OGNL processing assumes the * exlcusion of synthetic methods in order to process correctly. Only * use this method to determine method callability for any OGNL processing * after careful consideration. - * + * * This method considers synthetic methods that are not also bridge methods * as being un-callable. - * + * * Synthetic methods should be excluded in general, since calling such methods * could introduce unanticipated risks. - * + * * @since 3.2.16 * * @param m The method to check. @@ -2787,7 +2770,7 @@ static boolean isMethodCallable_BridgeOrNonSynthetic(Method m) { /** * cache get methods - * + * * @param context the current execution context. * @param targetClass the Class to invoke the property name "getter" retrieval on. * @param propertyName the name of the property for which a "getter" is sought. @@ -2887,7 +2870,7 @@ public static boolean hasGetMethod(OgnlContext context, Object target, Class tar /** * cache set methods method - * + * * @param context the current execution context. * @param targetClass the Class to invoke the property name "setter" retrieval on. * @param propertyName the name of the property for which a "setter" is sought. @@ -3163,7 +3146,7 @@ public static Map getPropertyDescriptors(Class targetClass) /** * This method returns a PropertyDescriptor for the given class and property name using a Map * lookup (using getPropertyDescriptorsMap()). - * + * * @param targetClass the class to get the descriptors for. * @param propertyName the property name of targetClass for which a Descriptor is requested. * @return the PropertyDescriptor for propertyName of targetClass. @@ -3394,7 +3377,7 @@ public static void setProperty(OgnlContext context, Object target, Object name, * then this will return whether it is a JavaBeans indexed property, conforming to the indexed * property patterns (returns INDEXED_PROPERTY_INT) or if it conforms to the * OGNL arbitrary object indexable (returns INDEXED_PROPERTY_OBJECT). - * + * * @param context the current execution context. * @param sourceClass the Class to invoke indexed property type retrieval on. * @param name the name of the property for which an indexed property type is sought. @@ -3557,7 +3540,7 @@ public static Method getMethod(OgnlContext context, Class target, String name, for (int i = 0; i < methods.size(); i++) { Method m = (Method) methods.get(i); - boolean varArgs = isJdk15() && m.isVarArgs(); + boolean varArgs = m.isVarArgs(); if (parms.length != m.getParameterTypes().length && !varArgs) continue; diff --git a/src/test/java/org/ognl/test/VarArgsMethodTest.java b/src/test/java/org/ognl/test/VarArgsMethodTest.java index aa4a6ba9..c3605beb 100644 --- a/src/test/java/org/ognl/test/VarArgsMethodTest.java +++ b/src/test/java/org/ognl/test/VarArgsMethodTest.java @@ -27,10 +27,45 @@ public class VarArgsMethodTest extends TestCase { private static Simple ROOT = new Simple(); public void testNullVarArgs() throws OgnlException { - Object value = Ognl.getValue("isThisVarArgsWorking()", new HashMap(), ROOT); + Object value = Ognl.getValue("isNullVarArgs()", new HashMap(), ROOT); - assertTrue(value instanceof Boolean); - assertTrue((Boolean) value); + assertTrue(value instanceof String); + assertEquals("null", value); + } + + public void testVarArgsWithSingleArg() throws Exception { + Object value = Ognl.getValue("isStringVarArgs(new String())", new HashMap(), ROOT); + + assertTrue(value instanceof String); + assertEquals("args", value); + } + + public void testVarArgsWithMultipleArgs() throws Exception { + Object value = Ognl.getValue("isStringVarArgs(new String(), new String())", new HashMap(), ROOT); + + assertTrue(value instanceof String); + assertEquals("args", value); + } + + public void testNestedNullVarArgs() throws OgnlException { + Object value = Ognl.getValue("get().request()", new HashMap(), ROOT); + + assertTrue(value instanceof String); + assertEquals("null", value); + } + + public void testNestedSingleVarArgs() throws OgnlException { + Object value = Ognl.getValue("get().request(new String())", new HashMap(), ROOT); + + assertTrue(value instanceof String); + assertEquals("args", value); + } + + public void testNestedMultipleVarArgs() throws OgnlException { + Object value = Ognl.getValue("get().request(new String(), new String())", new HashMap(), ROOT); + + assertTrue(value instanceof String); + assertEquals("args", value); } } diff --git a/src/test/java/org/ognl/test/objects/Simple.java b/src/test/java/org/ognl/test/objects/Simple.java index 18731658..23147ae3 100644 --- a/src/test/java/org/ognl/test/objects/Simple.java +++ b/src/test/java/org/ognl/test/objects/Simple.java @@ -243,4 +243,34 @@ public boolean isThisVarArgsWorking(Object...arguments) { return true; } + + public String isNullVarArgs() { + return "null"; + } + + public String isStringVarArgs(String... arguments) + { + return "args"; + } + + public TestInterface get() { + return new TestInterface() { + @Override + public String request() { + return "null"; + } + @Override + public String request(Object... args) { + return "args"; + } + }; + } + + interface TestInterface { + + String request(); + String request(Object... args); + + } + }