orphan-oss / ognl Goto Github PK
View Code? Open in Web Editor NEWObject Graph Navigation Library
Home Page: https://orphan.software
License: Apache License 2.0
Object Graph Navigation Library
Home Page: https://orphan.software
License: Apache License 2.0
I have a class that has 2 parameters:
Configure<Parent, Child>
which has method
setParent(Parent p)
and a concrete implementation ConfigureProfileItems extends Configure<Profile, Item>.
When OgnlRuntime enters the findParameterTypes() method the first time it determines that the parameter type should be {Profile} and caches it appropriately. The second time it enters this method it looks up the generic methods cache and compares this to the GenericTypes of the strutsAction.getGenericSuperClass() i.e. comparing {Profile} to {Profile, Item}. This fails and therefore has to recomputed every single time for this method.
Furthermore I have another class that extends ConfigureProfileItems therefore type.getGenericSuperclass() == null, so it is determined that the setParent() only parameter is an Object when the only parameter should be a Profile (since it extends ConfigureProfileItems).
Here is a suggested fix for this method that will determine the parameter types correctly and cache them correctly.
public class OgnlRuntime {
private static class GenericMethodParamKey {
Class<?> actionClass;
Method m;
private GenericMethodParamKey(Class<?> actionClass, Method m) {
this.actionClass = actionClass;
this.m = m;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((actionClass == null) ? 0 : actionClass.getName().hashCode());
result = prime * result + ((m == null) ? 0 : m.hashCode());
return result;
}
}
private static Hashtable<Method, Class<?>[]> nonGenericMethodParams = new Hashtable<Method, Class<?>[]>();
private static Hashtable<GenericMethodParamKey, Class<?>[]> genericMethodParams = new Hashtable<GenericMethodParamKey, Class<?>[]>();
public static Class<?>[] findParameterTypes(Class<?> clazz, Method m) {
// Check the non generic methods
Class<?>[] types = nonGenericMethodParams.get(m);
if (types != null) {
return types;
}
// Check the generic methods
GenericMethodParamKey key = new GenericMethodParamKey(clazz, m);
types = genericMethodParams.get(key);
if (types != null) {
return types;
}
Type[] params = determineMethodParams(clazz, m);
types = new Class<?>[params.length];
boolean nonGeneric = true;
// replace any parameters on the method with their bound types
for (int i = 0; i < types.length; i++) {
Type type = params[i];
if (type instanceof Class<?>) {
Class<?> paramClass = (Class<?>) type;
types[i] = paramClass;
} else {
Class<?> paramClass = m.getParameterTypes()[i];
types[i] = paramClass;
}
nonGeneric = nonGeneric && types[i] == m.getParameterTypes()[i];
}
if (nonGeneric) {
nonGenericMethodParams.put(m, types);
} else {
genericMethodParams.put(key, types);
}
return types;
}
/**
* This method gets the method parameters for method m called from class clazz, replacing any generic types
* that are class-wide parameters.
*
* If the method has any parameterization of its own, these types are still present in the result
* @param clazz
* @param m
* @return
*/
private static Type[] determineMethodParams(Class<?> clazz, Method m) {
// If this class is the methods declaring class then get the generic method parameters
if (m.getDeclaringClass() == clazz) {
return getMethodParameterTypes(m);
}
// Get the parameter types as defined in clazz's super class
Class<?> superClazz = clazz.getSuperclass();
Type[] types = determineMethodParams(superClazz, m);
// replace the parameter types with overriding clazz's parameters
Type superClass = clazz.getGenericSuperclass();
if (superClass != null && ParameterizedType.class.isInstance(superClass)) {
ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) superClass;
// Compare Class2<S,T> and Class1<E,F> extends Class2<F,Integer> to replace
// any Class2 variable S with Class1 variable F and Class2 variable T with java.lang.Integer
Type[] actualTypes = parameterizedType.getActualTypeArguments();
TypeVariable<?>[] classTypes = clazz.getSuperclass().getTypeParameters();
for (int i = 0; i < types.length; i++) {
Type type = types[i];
for (int j = 0; j < actualTypes.length; j++) {
TypeVariable<?> classType = classTypes[j];
if (type.toString().equals(classType.getName())) {
// Generic method parameter is being overridden by subclass
types[i] = actualTypes[j];
}
}
}
}
return types;
}
/**
* This method gets the generic parameter types of a method
* @param method
*/
private static Type[] getMethodParameterTypes(Method method) {
// Get Generic Types
Type[] types = method.getGenericParameterTypes();
// Replace any bounds where method like public <T extends E> void doSomething(T t); where
// E is a class parameter
TypeVariable<?>[] vars = method.getTypeParameters();
for (int i = 0; i < types.length; i++) {
Type type = types[i];
for (int j = 0; j < vars.length; j++) {
TypeVariable<?> typeVariable = vars[j];
if (typeVariable.getName().equals(type.toString())) {
types[i] = typeVariable.getBounds()[0];
// Reset j incase we have a case where public <T extends E, S extends T> void doSomething(S s);
j = -1;
type = types[i];
}
}
}
return types;
}
}
RT, and code is here
protected String generateSetter(OgnlContext context, CtClass newClass, CtClass objClass, ClassPool pool,
CtMethod valueSetter, Node expression, Object root)
throws Exception
{
if (ExpressionNode.class.isInstance(expression)
|| ASTConst.class.isInstance(expression))
throw new UnsupportedCompilationException("Can't compile expression/constant setters.");
...
return body;
}
Greetings,
I first reported this issue in mybatis/mybatis-3#2421 but then I realized it might be more appropriate here.
When I have some sql statements containing <if test="_parameter.containsKey('foo')">
and the parameters are in a Collections.singletonMap
I get the following warning in the console:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by ognl.AccessibleObjectHandlerPreJDK9 (file:/C:/Users/shenz/.m2/repository/ognl/ognl/3.3.1/ognl-3.3.1.jar) to method java.util.Collections$SingletonMap.containsKey(java.lang.Object)
WARNING: Please consider reporting this to the maintainers of ognl.AccessibleObjectHandlerPreJDK9
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
This does not happen when using java.util.Map
.
I am using Java 11.0.13.
I would like to move this project under Softwaremill's umbrella - we have a large experience in maintaining Open Source projects and supporting open source projects is one of our core values :)
At the same time I would like to request ASF to drop Commons-OGNL as this is outdated and unsupported project, tbh :(
Any objections @jkuhnert @harawata @JCgH4164838Gh792C124B5 @yasserzamani and others?
You have migrated to Apache 2.0 license but Copyright notices in the source file still referring to earlier license which was not Apache 2.0. Please update all source files to include Apache 2.0 Copyright notice.
I want to use the API 'OGNL.getValue' get specific value from an object, some properties in the object have symbol ‘/’, the problem 'java.lang.ArithmeticException: / by zero' will occur when call the API 'OGNL.getValue', is there some solutions to solve this problem?
Hi,
in class OnglRuntime, method capitalizeBeanPropertyName
the code:
char first = propertyName.charAt(0);
char second = propertyName.charAt(1);
if ((Character.isLowerCase(first)) && (Character.isUpperCase(second))) {
return propertyName;
}
char[] chars = propertyName.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
when i define a field name "iType" and setter method setIType(eclipse automatic generated setter method), then capitalizeBeanPropertyName method return "iType", this results method "_getSetMethod" cann't find the setter method for "iType".
the further infuence, struts2 2.3.28 reference the ongl library 3.0.14, when I defined a field the name such as "iType" in a Action class, the i can't auto inject the request parameter for "iType".
I find the ognl version "3.0.6" has not the problem. I find this issue just when i upgrade struts2 from version 2.3.15 to 2.3.28.
Please check the problem if it exists, Thanks in advance!
I have a method
interface Accessible {
default Accessible access(Object... args) {
return /* whatever */;
}
}
When calling access() without arguments, a java.lang.NoSuchMethodException is thrown because the varargs method is not found.
MemberAccess support private static method and private field, but do not support private static field.
Demo:
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.Map;
import ognl.ClassResolver;
import ognl.MemberAccess;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
public class MyDemo {
private static String statidField = "fff";
private String privateField = "ppp";
private static String staticFunc() {
return "static func";
}
private static MyDemo newInstance() {
return new MyDemo();
}
public static void main(String[] args) throws OgnlException {
OgnlContext context = new OgnlContext(new ClassResolver() {
@Override
public Class classForName(String className, Map context) throws ClassNotFoundException {
return Class.forName(className);
}
}, null, new DefaultMemberAccess(true));
context.setTraceEvaluations(true);
Object root = null;
System.out.println(Ognl.getValue("@MyDemo@staticFunc()", context, root));
System.out.println(Ognl.getValue("@MyDemo@newInstance().privateField", context, root));
// exception
System.out.println(Ognl.getValue("@MyDemo@statidField", context, root));
}
public static class DefaultMemberAccess implements MemberAccess {
public boolean allowPrivateAccess = false;
public boolean allowProtectedAccess = false;
public boolean allowPackageProtectedAccess = false;
/*
* ===================================================================
* Constructors
* ===================================================================
*/
public DefaultMemberAccess(boolean allowAllAccess) {
this(allowAllAccess, allowAllAccess, allowAllAccess);
}
public DefaultMemberAccess(boolean allowPrivateAccess, boolean allowProtectedAccess,
boolean allowPackageProtectedAccess) {
super();
this.allowPrivateAccess = allowPrivateAccess;
this.allowProtectedAccess = allowProtectedAccess;
this.allowPackageProtectedAccess = allowPackageProtectedAccess;
}
/*
* =================================================================== Public
* methods ===================================================================
*/
public boolean getAllowPrivateAccess() {
return allowPrivateAccess;
}
public void setAllowPrivateAccess(boolean value) {
allowPrivateAccess = value;
}
public boolean getAllowProtectedAccess() {
return allowProtectedAccess;
}
public void setAllowProtectedAccess(boolean value) {
allowProtectedAccess = value;
}
public boolean getAllowPackageProtectedAccess() {
return allowPackageProtectedAccess;
}
public void setAllowPackageProtectedAccess(boolean value) {
allowPackageProtectedAccess = value;
}
/*
* ===================================================================
* MemberAccess interface
* ===================================================================
*/
public Object setup(Map context, Object target, Member member, String propertyName) {
Object result = null;
if (isAccessible(context, target, member, propertyName)) {
AccessibleObject accessible = (AccessibleObject) member;
if (!accessible.isAccessible()) {
result = Boolean.TRUE;
accessible.setAccessible(true);
}
}
return result;
}
public void restore(Map context, Object target, Member member, String propertyName, Object state) {
if (state != null) {
((AccessibleObject) member).setAccessible(((Boolean) state).booleanValue());
}
}
/**
* Returns true if the given member is accessible or can be made accessible by
* this object.
*/
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
int modifiers = member.getModifiers();
boolean result = Modifier.isPublic(modifiers);
if (!result) {
if (Modifier.isPrivate(modifiers)) {
result = getAllowPrivateAccess();
} else {
if (Modifier.isProtected(modifiers)) {
result = getAllowProtectedAccess();
} else {
result = getAllowPackageProtectedAccess();
}
}
}
return result;
}
}
}
Output:
static func
ppp
Exception in thread "main" ognl.OgnlException: Could not get static field statidField from class MyDemo [java.lang.NoSuchFieldException: statidField]
at ognl.ASTStaticField.isNodeConstant(ASTStaticField.java:108)
at ognl.SimpleNode.isConstant(SimpleNode.java:325)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:202)
at ognl.SimpleNode.getValue(SimpleNode.java:236)
at ognl.Ognl.getValue(Ognl.java:493)
at ognl.Ognl.getValue(Ognl.java:595)
at ognl.Ognl.getValue(Ognl.java:565)
at MyDemo.main(MyDemo.java:42)
Caused by: java.lang.NoSuchFieldException: statidField
at java.lang.Class.getField(Class.java:1703)
at ognl.ASTStaticField.isNodeConstant(ASTStaticField.java:92)
... 7 more
/-- Encapsulated exception ------------\
java.lang.NoSuchFieldException: statidField
at java.lang.Class.getField(Class.java:1703)
at ognl.ASTStaticField.isNodeConstant(ASTStaticField.java:92)
at ognl.SimpleNode.isConstant(SimpleNode.java:325)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:202)
at ognl.SimpleNode.getValue(SimpleNode.java:236)
at ognl.Ognl.getValue(Ognl.java:493)
at ognl.Ognl.getValue(Ognl.java:595)
at ognl.Ognl.getValue(Ognl.java:565)
at MyDemo.main(MyDemo.java:42)
\--------------------------------------/
When I try to upgrade objectify from 3.1.X to 3.2.X. The following code breaks.
public class Demo {
public void test() {
OgnlContext ctx = new OgnlContext();
}
}
The code should pass, but it throws an error:
Demo.java:[11,20] error: no suitable constructor found for OgnlContext(no arguments)
I impliment a ClassResolver that imports a custom package other than java.lang
.
It throws when compiling expression calling static method of class under my custom package.
Express is like this @Calbit@cal(x)
, and the package path is cn.agentd.ognl.util
.
stacktrace
Exception in thread "main" javassist.CannotCompileException: [source error] no such class: Calbit
at javassist.CtBehavior.setBody(CtBehavior.java:474)
at javassist.CtBehavior.setBody(CtBehavior.java:440)
at ognl.enhance.ExpressionCompiler.generateGetter(ExpressionCompiler.java:553)
at ognl.enhance.ExpressionCompiler.compileExpression(ExpressionCompiler.java:419)
at ognl.OgnlRuntime.compileExpression(OgnlRuntime.java:435)
at ognl.Ognl.compileExpression(Ognl.java:141)
at cn.agentd.ognl.Demo.main(Demo.java:27)
Caused by: compile error: no such class: Calbit
at javassist.compiler.MemberResolver.searchImports(MemberResolver.java:479)
at javassist.compiler.MemberResolver.lookupClass(MemberResolver.java:422)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:683)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
at javassist.compiler.JvstTypeChecker.atCastToWrapper(JvstTypeChecker.java:138)
at javassist.compiler.JvstTypeChecker.atCastExpr(JvstTypeChecker.java:110)
at javassist.compiler.ast.CastExpr.accept(CastExpr.java:59)
at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:266)
at javassist.compiler.CodeGen.compileExpr(CodeGen.java:253)
at javassist.compiler.CodeGen.atReturnStmnt2(CodeGen.java:641)
at javassist.compiler.JvstCodeGen.atReturnStmnt(JvstCodeGen.java:443)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:393)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:381)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
at javassist.compiler.CodeGen.atMethodBody(CodeGen.java:321)
at javassist.compiler.Javac.compileBody(Javac.java:228)
at javassist.CtBehavior.setBody(CtBehavior.java:466)
... 6 more
If we have a public code
field in a class, such as:
public class Something {
public String code = "abc123";
}
And, being s
an object of type Something
, we execute this expression:
s.code
Instead of returning "abc123"
, the hash code will be returned because the hashCode()
method will be selected for execution.
The responsible for this is this block of code in OgnlRuntime
: https://github.com/jkuhnert/ognl/blob/751084b4802b488e0386ab702e230cceca296254/src/java/ognl/OgnlRuntime.java#L2947-L2954
if (methods[i].getName().toLowerCase().endsWith(name)
&& !methods[i].getName().startsWith("set")
&& methods[i].getMethod().getReturnType() != Void.TYPE) {
Method m = methods[i].getMethod();
if (!candidates.contains(m))
candidates.add(m);
}
IMHO the check applied here is far too lenient, especially given the fact that field names have not been checked yet by the time this executes…
Is there a reason for why some AST nodes are not public?
E.g.ASTEq
, ASTAdd
are private
but e.g. ASTChain
, ASTCtor
, ASTProperty
are public.
This makes it impossible to create a visitor, unless I put it into ognl
package itself.
OGNL currently evaluates String
objects with any value to true
, but this makes OGNL's boolean coercion incompatible with two other very used Expression Languages: JSP EL and Spring EL, both of which would evaluate "true"
and "false"
as booleans true
and false
, respectively (even if they diverge in their evaluation of other non-booleanish String
values).
It would be great if OGNL modified this behaviour in order to evaluate "false"
as false
(and better even if "off"
and "no"
were included in the pack, but that might be asking too much ;-)).
For me, it would allow me to remove this hugely ugly, javassist-based hack from thymeleaf: https://github.com/thymeleaf/thymeleaf/blob/159f963907e9d5e3943843031845df28934adafc/src/main/java/org/thymeleaf/standard/expression/OgnlVariableExpressionEvaluator.java#L201-L261
Hi,
when trying to access a BeanFactory with factory.getBean("test")
an ArrayIndexOutOfBoundsExceptions is thrown:
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1265)
at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
at ognl.ASTMethod.getValueBody(ASTMethod.java:90)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTChain.getValueBody(ASTChain.java:141)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTMethod.getValueBody(ASTMethod.java:87)
...
I created a small Dummy-BeanFactory to reproduce the issue:
package org.ognl.test.objects;
import java.util.Arrays;
public class BeanFactory {
//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------
public Object getBean(String name) {
return "NamedBean: "+name;
}
public <T> T getBean(String name, Class<T> requiredType) {
return (T) ("NamedTypedBean: "+name+" "+requiredType.getSimpleName());
}
public <T> T getBean(Class<T> requiredType) {
return (T) ("TypedBean: "+requiredType.getSimpleName());
}
public Object getBean(String name, Object... args) {
return "NamedBeanWithArgs: "+name+" "+Arrays.toString(args);
}
}
.. might also be related to the issue in #16
Hi,
I note that the Apache commons ognl library hasn't had an update in about 2 years, but this library has. Is this just because the 4.0 (commons) lib is seen is super stable and needs no fixes, or is choosing to depend on this library due to the ongoing support / fixes etc. for a new project the right choice?
Hi,
I just pushed a new branch that also addresses another 'inconsistency' issue I was fighting in the past:
The automatic Type-Conversion puts a List (or Collection) into an array by doing new Object[] { } instead of using the items of the list for the array. I think this would be the more desired behaviour. I also fixed the related unit tests from #16 / #19 respectively and added some new tests.
The commit [410dee5](secadm@410dee5f64410f98ad4171150dc19869abd7de4c] (branch TypeConverterDoubleArrayBoxing) addresses the issue.
This patch is based on #23 / #24 and so i'll create a pull request after #24 ist merged or the pull request will also provide #24. But maybe both requests can be reviewed together.
Bye,
Chris
Is correct following code?
Should be set the Boolean.FALSE
in this case?
WDYT?
The OgnlRuntime.clearCache() method does not empty the cacheSetMethod and cacheGetMethod caches. The inability to clear this cache is leading to the following error:
java.lang.IllegalArgumentException: object is not an instance of declaring class
It appears that the issue occurs when classes are reloaded by a different classloader. If we had the ability to clear the caches mentioned above we believe it would fix our issue.
In our case we are using Spring Boot Dev Tools. When the application restarts and classes are reloaded we have no way to clear the caches mentioned above.
Relates to OGNL-257
With the newly introduced check for arithmetic expressions, negative numbers are considered to be arithmetic expressions.
I can understand that one does not want to have arithmetic expressions in parameter names. OTOH, I would not consider a negative number as an arithmetic expression.
Note that this has also been reported to the struts2 project under https://issues.apache.org/jira/browse/WW-4651
@lukaszlenart asked me to post this here as well.
<url>http://ognl.org</url>
https://github.com/jkuhnert/ognl/blob/598897f2c1bcf39e41ef0fa0f5c361f2d9d84ea2/pom.xml#L19
I wrote unicode test case
public class InExpressionUnicodeTest extends TestCase {
public void test_String_In()
throws Exception
{
OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null);
Object node = Ognl.parseExpression("#이름 in {\"홍길동\", \"둘리\", \"Africa\", \"Rome\"}");
Object root = null;
context.put("이름", "홍길동");
assertEquals(Boolean.TRUE, Ognl.getValue(node, context, root));
}
}
OGNL throw Exception
ognl.ExpressionSyntaxException: Malformed OGNL expression: #이름 in {"홍길동", "둘리", "Africa", "Rome"} [ognl.TokenMgrError: Lexical error at line 1, column 2. Encountered: "\uc774" (51060), after : ""]
I debugging codes, and I modify OgnlParserTokenManager.java
Modify line 786
else if (curChar < 128) -> else
Delete line 853-875
after that modification, almost every test case success include my unicode test.
I guess, OgnlParserTokenManager work well with only ascii ( < 128)
(I modify OgnlParserTokenManager.java it self, because I don't know how to use JavaCC. (I don't know how to fix ognl.jj ognl.jjt)
Here is my proposal:
add
if (Modifier.isPublic(method.getModifiers()) && Modifier.isPublic(method.getDeclaringClass().getModifiers()))
{
// real public method should invoke directly
return method.invoke(target, argsArray);
}
@yasserzamani @lukaszlenart WDYT?
In this commit e30b211 OgnlContext(MemberAccess memberAccess, ClassResolver classResolver, TypeConverter typeConverter, Map values)
was updates to throw an exception if memberAccess
is null
.
The constructor OgnlContext(Map values)
always passes null and thus cannot ever work.
This impacts Thymeleaf since it calls OgnlContext(Map values)
from its OGNL expression code.
In order to have the OGNL jar artifact properly work as a dependency in JPMS (a required module in a Java 9+ modular application), OGNL should choose a module name that gives dependent software some kind of guarantee on the module name that should be used for it, whatever the version. This can be done even if OGNL is not turned yet into a module as such, by merely adding an Automatic-Module-Name: <name>
entry to the MANIFEST.MF
file.
This works as a kind of reserve for module names and allows software using OGNL to properly express OGNL as a dependency in a requires
clause in module-info.java
, even if OGNL has not been modularised yet.
Note there are two main approaches for module naming (see this). Apache Commons OGNL has already chosen the reverse-DNS approach (see their pom.xml) so it is org.apache.commons.ognl
there, but given OGNL 3 and OGNL 4 will be completely package- and code-incompatible (ognl.*
vs org.apache.commons.ognl.*
packages), I'm not sure it would make sense to adopt org.apache.commons.ognl
here too as a module name for the sake of compatibility. So using simply ognl
as name could be a sensible option here too. Especially given the fact that Apache Commons OGNL seems dead.
Here is a repro:
@Test
public void test() throws Exception {
String expressiosn = "list.isEmpty()";
Object expr = Ognl.parseExpression(expressiosn);
OgnlContext ctx = new OgnlContext();
List<String> list = Collections.singletonList("string");
ctx.put("list", list);
Object value = Ognl.getValue(expr, ctx);
Assert.assertFalse((Boolean)value);
}
The above test passes, but the following message is output in System.err.
Two methods with same method signature but not providing classes assignable? "public abstract boolean java.util.List.isEmpty()" and "public boolean java.util.AbstractCollection.isEmpty()" please report!
This was reported on MyBatis tracker a while ago.
Fail to invoke a varargs setter method via Ognl#setValue
as follow:
package org.ognl.test.issues;
import ognl.DefaultMemberAccess;
import ognl.Ognl;
import ognl.OgnlException;
import org.hamcrest.core.IsEqual;
import org.junit.Assert;
import org.junit.Test;
public class ReproTest {
@Test // Success
public void testForArray() throws OgnlException, NoSuchMethodException {
Bean bean = new Bean();
Ognl.setValue("chars", Ognl.createDefaultContext(null, new DefaultMemberAccess(false)), bean, new Character[]{'%', '_'});
Assert.assertThat(bean.chars.length, IsEqual.equalTo(2));
Assert.assertThat(bean.chars[0], IsEqual.equalTo('%'));
Assert.assertThat(bean.chars[1], IsEqual.equalTo('_'));
}
@Test // Fail
public void testForVarArgs() throws OgnlException, NoSuchMethodException {
Bean bean = new Bean();
Ognl.setValue("strings", Ognl.createDefaultContext(null, new DefaultMemberAccess(false)), bean, new String[]{"%", "_"});
Assert.assertThat(bean.strings.length, IsEqual.equalTo(2));
Assert.assertThat(bean.strings[0], IsEqual.equalTo("%"));
Assert.assertThat(bean.strings[1], IsEqual.equalTo("_"));
}
static class Bean {
private Character[] chars;
private String[] strings;
public void setChars(Character[] chars) {
this.chars = chars;
}
public Character[] getChars() {
return chars;
}
public void setStrings(String... strings) {
this.strings = strings;
}
public String[] getStrings() {
return strings;
}
}
}
Perhaps the implementation of the methods around here will have an impact.
Only in this case:
enum Op {
NE("<>"), // getClass() is "Op$1"
EQ("=") // getClass() is "Op$2"
}
Op.NE.getClass(). isAssignableFrom(Op.EQ.getClass()) // false
OgnlOps#isEqual(Object, Object) // line 124
is
result = (object1 != null) && (object2 != null)
&& (object1.equals(object2) || (compareWithConversion(object1, object2) == 0));
OgnlOps#compareWithConversion(Object, Object) // line 87 ~ 95
if ((t1 == NONNUMERIC) && (t2 == NONNUMERIC)) {
// **FIXME: when enum is abstract**
if ((v1 instanceof Comparable) && v1.getClass().isAssignableFrom(v2.getClass())) {
result = ((Comparable) v1).compareTo(v2);
break;
} else {
throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and "
+ v2.getClass().getName());
}
}
Temporary solution
"Op.NE.name() == 'NE'"
before version is ok;
OgnlOps#isEqual(Object, Object)
result = compareWithConversion(object1, object2, true) == 0 || object1.equals(object2);
OgnlOps#compareWithConversion(Object, Object, boolean)
if(!equals) { // **HERE because equals args is true **
throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
}
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by ognl.OgnlRuntime (file:XXXXXXXXXXXXXXXXXXXXXX/WEB-INF/lib/ognl-3.0.21.jar) to method java.util.HashMap$Node.getValue()
WARNING: Please consider reporting this to the maintainers of ognl.OgnlRuntime
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
This warning message happens while I was running java 15. But since java 16 on wards struts-jquery-chart-tags stop working because they rely on ognl to assign dynamic data value. Access operation to to method java.util.HashMap$Node.getValue() is denied.
Is there any solution or idea?
I am running ognl 3.2.1.
Higher releases shows us the error below:
java.lang.NoClassDefFoundError: ognl/DefaultMemberAccess
Our logs are being flooded with the message:
Two methods with same score(0): "public java.lang.String myPackage.MyClass.myMethod(myPackage.MyModelClass,int)" and "public abstract java.lang.String myPackage.MyClassAbstract.myMethod(java.lang.Object,int)" please report!
We are on the latest version of struts (struts2-core-2.5.14.jar) which uses ognl-3.1.15.
This issue seems to come from OgnlRuntime.java at line 1430.
I grepped on future versions of OgnlRuntime.java from your github for 'abstract' ignoring case and found code in 3.1.16 and 3.2.3, and 3.2.4. I tried applying the logic from these code fixes in a locally compiled OgnlRuntime, but the problem did not go away. I don't completely understand your score calculation, but some of the other flags (isInterface, etc) seem to preclude our implementation.
The only thing I could do to workaround this was to put above this sysout line:
if (!Modifier.isAbstract(m.getModifiers()))
Our implementation is:
<<MyClassAbstract.java>>
package myPackage;
public abstract class MyClassAbstract {
public abstract String myMethod (E element, int i);
<<MyClass.java>>
package myPackage;
public class MyClass extends MyClassAbstract < MyModelClass > {
public String myMethod (MyModelClass myModel, int i) {
Please advise.
It may need to be redesigned
Hi,
When doing a "mvn test" with Java 8 the tests fail with these error messages:
Results :
Failed tests:
messages.format('ShowAllCount', one) (foo)(org.ognl.test.MethodTest)
Tests in error:
{'1','2','3'}(org.ognl.test.ArrayElementsTest)
{ true, !false }(org.ognl.test.ArrayElementsTest)
{stringValue, getMap()}(org.ognl.test.PropertyTest)
{'stringValue', map["test"].map["size"]}(org.ognl.test.PropertyTest)
test_Complicated_List(org.ognl.test.ASTPropertyTest)
null in {true,false,null} (true)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
null not in {true,false,null} (false)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5 in {true,false,null} (false)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5 not in {true,false,null} (true)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
#y + "1" (11)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
"1" + #y (11)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
{ false, true, null, 0, 1. } ([false, true, null, 0, 1.0])(org.ognl.test.ConstantTest)
messages.format('ShowAllCount', {one}) (foo)(org.ognl.test.MethodTest)
messages.format('ShowAllCount', {one, two}) (foo)(org.ognl.test.MethodTest)
{theInt + 1}(org.ognl.test.PropertyArithmeticAndLogicalOperatorsTest)
Tests run: 730, Failures: 1, Errors: 15, Skipped: 0
In the logs we see a lot of messages like:
Running org.ognl.test.ArrayElementsTest
Caught exception java.lang.RuntimeException: java.io.IOException: invalid constant type: 18
Caught exception java.lang.RuntimeException: java.io.IOException: invalid constant type: 18
Tests run: 11, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.026 sec <<< FAILURE!
The invalid constant type exception referes to Java 8 classes. Okay, OGNL uses javassist to access the java objects. The utilized version is 3.11, which dosn't support Java 8.
Updating javassist 3.11.0.GA to 3.20.0-GA changes the error message:
Results :
Failed tests:
messages.format('ShowAllCount', one) (foo)(org.ognl.test.MethodTest)
messages.format('ShowAllCount', {one}) (foo)(org.ognl.test.MethodTest)
messages.format('ShowAllCount', {one, two}) (foo)(org.ognl.test.MethodTest)
Tests run: 730, Failures: 3, Errors: 0, Skipped: 0
When using java 1.7 all tests pass. Amazing ;)
So I did some further investigations and this are my findings:
For Java 1.8 the message.format calls resulted in those function calls:
messages.format('ShowAllCount', one) -> calls format(String key, Object param1)
messages.format('ShowAllCount', {one}) -> calls format(String key, Object param1)
param1 is Array[1]... Okay, Array matches to object...
messages.format('ShowAllCount', {one, two}) -> calls format(String key, Object param1)
param1 is Array[1, 2]... Okay, Array matches to object...
Then I found out following facts;
.getMessages()).format("ShowAllCount", (java.lang.Object[]) ref1($$))
.getMessages()).format("ShowAllCount", ($w) ((org.ognl.test.objects.Simple)$2)..getOne())
public java.lang.String org.ognl.test.objects.Messages.format(java.lang.String,java.lang.Object[])
public java.lang.String org.ognl.test.objects.Messages.format(java.lang.String,java.lang.Object)
Okay, the root cause is: OgnlRuntime.getReadMethod() obtains a list of methods by calling
BeanInfo info = Introspector.getBeanInfo(target);
MethodDescriptor[] methods = info.getMethodDescriptors();
and iterating through this list, returning the first method that could propably match. And info.getMethodDescriptors() returns the list in a different order depending on the java version.
Okay, how to solve this?
My only idea would be to extend this getReadMethod() with following functionallity:
Any other ideas?
I want to use the OGNL on my Android Project,
and I add the dependency in my project's build.gradle.
but it throw an exception:
ognl.OgnlException: alias [java.lang.RuntimeException: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/beans/Introspector;]。
How can I solve this problem?
I got a problem while using struts2 2.5.9 and struts2-jquery-plugin 4.0.3.
Actionmessages and actionErrors does not show up anymore. FieldError is displayed saying that value type for this fields (actionmessages and actionerrors) are not valid.
I read 2.5 api and nothing changed about it. addActionMessage() and addActionError() still receive a String as argument.
No exception is thrown. I do think the problem - if there is some - may be struts2-jquery-plugin 4.0.3. This jar contains jquery-2.2.4 which is a vulnerable version of jquery, and looking for something in google dev tools I got this:
<!DOCTYPE html>
to render the page in No Quirks Mode.AFFECTED RESOURCES:
Document in the DOM tree | Mode | URL |
---|---|---|
document | Limited Quirks Mode | http://localhost:8080/ProjXXXXX/registerCostumer.action?actionErrors=Client+already+registered. |
What the server got is:
xxxxxxxxxx.action?actionErrors=No+results+for+this.+
The message passed to addActionError is ok. But it does not show, instead a fieldError.
Any idea about this? I tried to look for validations for the fields actionmessages and errormessages in the project and found nothing.
It is like some validation is going on and failed because I got the message from messages.properties for every invalid field Value:
xwork.default.invalid.fieldvalue = Invalid Value for this field {0}
In OGNL 3.2.20 I'm experiencing the following log message. I think this error may be spurious here since there's a no-args method as well as 2 varargs methods.
Two vararg methods with same score(0): "public javax.ws.rs.client.Invocation$Builder org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.request(javax.ws.rs.core.MediaType[])" and "public javax.ws.rs.client.Invocation$Builder org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.request(java.lang.String[])" please report!
The OGNL statement being executed is:
someWebTarget.request().get()
Here's the method being called: https://github.com/resteasy/Resteasy/blob/main/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ClientWebTarget.java#L358
Tested with 3.2.14.
Calling Ognl.getValue(Object, Object, Class)
calls Ognl.createDefaultContext(Object)
(which is marked as deprecated). This then calls constructor OgnlContext(ClassResolver, TypeConverter, MemberAccess)
with all null
arguments, which finally calls the other constructor OgnlContext(MemberAccess, ClassResolver, TypeConverter, Map)
which throws IllegalArgumentException("MemberAccess implementation must be provided - null not permitted!")
.
I'm not sure whether the internal use of a deprecated call is a bug (deprecated is not supposed to mean broken, after all), or whether further overloads of Ognl.getValue
(I'm actually calling Ognl.getValue(String, Object)
which calls Ognl.getValue(String, Object, Class)
, which calls Ognl.getValue(Object, Object, Class)
) ought to have been deprecated (although ditto), or whether something else is amiss, but there is clearly an issue here.
The issue was introduced in version 3.2.2, in commit e30b211
List<String> list = Arrays.asList("a","b","c","d"); list.forEach(s -> System.out.println(s));
but it may cause Exception:
String expression = "{'a','b','c','d'}.foreach(s -> java.lang.System.out.println(s))"; Ognl.getValue(expression, context, root);
Hi,
We are using mybatis-3.3.0. Recently we got one strange error from mybatis code while executing a query that gets executed successfully many times during the day, but failed several times.
Below is the stacktrace:
org.apache.ibatis.ognl.NoSuchPropertyException: OrderEO.cinemaAddress
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:280) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:80) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:73) ~[mybatis-3.3.0.jar:3.3.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
... 36 more
Caused by: org.apache.ibatis.ognl.NoSuchPropertyException: OrderXEO.cinemaAddress
at org.apache.ibatis.ognl.ObjectPropertyAccessor.getProperty(ObjectPropertyAccessor.java:151) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.OgnlRuntime.getProperty(OgnlRuntime.java:2434) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTProperty.getValueBody(ASTProperty.java:114) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:141) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTNotEq.getValueBody(ASTNotEq.java:50) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:61) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:494) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:458) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:44) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:280) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:80) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:73) ~[mybatis-3.3.0.jar:3.3.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
Any help to find root cause of above error will be greatly appreciated.
Ps. We have met a similar problem when using mybatis-3.1.0, which has fixed in mybatis-3.3.0. Is this the similar cause of ognl?
It looks like that starting from OGNL 2.7 a dependency on javassist was introduced.
Many projects still use OGNL 2.6.9 but won't upgrade to 2.7.x or 3.0 (because of this too).
Please remove this dependency if it's possible.
If package name includes "or" (e.g. "jp.or.example"), the Ognl#parseExpression(String)
is failed as follow:
public void test_class_reference()
throws Throwable
{
OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null, new DefaultMemberAccess(false));
{
Node expr = (Node) Ognl.parseExpression("@java.util.UUID@randomUUID()"); // It's OK
Object v = expr.getValue(context, null);
System.out.println(v);
}
{
Node expr = (Node) Ognl.parseExpression("@jp.or.example.IdUtils@generateId()"); // It's failed on parsing phase
Object v = expr.getValue(context, null);
System.out.println(v);
}
}
ognl.ExpressionSyntaxException: Malformed OGNL expression: @jp.or.example.IdUtils@generateId()
[ognl.ParseException: Encountered " "or" "or "" at line 1, column 5.
Was expecting:
<IDENT> ...
]
at ognl.Ognl.parseExpression(Ognl.java:179)
at org.ognl.test.enhance.TestExpressionCompiler.test_class_reference(TestExpressionCompiler.java:55)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at junit.framework.TestCase.runTest(TestCase.java:176)
at junit.framework.TestCase.runBare(TestCase.java:141)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:129)
at junit.framework.TestSuite.runTest(TestSuite.java:252)
at junit.framework.TestSuite.run(TestSuite.java:247)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: ognl.ParseException: Encountered " "or" "or "" at line 1, column 5.
Was expecting:
<IDENT> ...
at ognl.OgnlParser.generateParseException(OgnlParser.java:3232)
at ognl.OgnlParser.jj_consume_token(OgnlParser.java:3098)
at ognl.OgnlParser.className(OgnlParser.java:1822)
at ognl.OgnlParser.classReference(OgnlParser.java:1795)
at ognl.OgnlParser.staticReference(OgnlParser.java:1762)
The example in the https://github.com/jkuhnert/ognl/blob/master/docs/DeveloperGuide.md#embedding-ognl uses deprecated code and should be updated:
public Object getValue(OgnlContext context, Object rootObject) throws OgnlException {
return Ognl.getValue(getExpression(), context, rootObject); // <-- deprecated
}
What is a non-deprecated alternative that resembles the same functionality?
I'm passing in some nulls in my varargs, which is legal. However they are being filtered out here. Is this intentional? This does not seem correct to me.
A single null would be ambiguous because it could be meant to be the array OR the array content, but multiple nulls are always interpreted as an array in java varargs.
I've performed the Java8Test
on local PC. But testGetDeclaredMethods
is failed.
Probably, the OgnlRuntime.getDeclaredMethods
cannot scan a declared method in a super interface.
Is this bug?
package ognl;
import java.beans.IntrospectionException;
import java.lang.reflect.Method;
import java.util.List;
import junit.framework.TestCase;
public class Java8Test extends TestCase {
public void testDefaultMethodOnClass() {
/* defaultMethod(); */
List defaultMethod = OgnlRuntime.getMethods(ClassWithDefaults.class, "defaultMethod", false);
assertNotNull(defaultMethod);
Method method = OgnlRuntime.getReadMethod(ClassWithDefaults.class, "defaultMethod");
assertNotNull(method);
}
public void testDefaultMethodOnSubClass() {
/* defaultMethod(); */
List defaultMethod = OgnlRuntime.getMethods(SubClassWithDefaults.class, "defaultMethod", false);
assertNotNull(defaultMethod);
Method method = OgnlRuntime.getReadMethod(SubClassWithDefaults.class, "defaultMethod");
assertNotNull(method);
}
public void testGetDeclaredMethods() throws IntrospectionException, OgnlException{
List defaultMethod = OgnlRuntime.getDeclaredMethods(SubClassWithDefaults.class, "name", false);
assertNotNull(defaultMethod);
defaultMethod = OgnlRuntime.getDeclaredMethods(ClassWithDefaults.class, "name", false);
assertNotNull(defaultMethod); // fail this line
}
}
class SubClassWithDefaults extends ClassWithDefaults {
public String getName() { return "name"; }
}
class ClassWithDefaults implements SubInterfaceWithDefaults {
}
interface InterfaceWithDefaults {
default public void defaultMethod() { }
default public String getName() { return "name"; }
}
interface SubInterfaceWithDefaults extends InterfaceWithDefaults {
}
junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:48)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertNotNull(Assert.java:218)
at junit.framework.Assert.assertNotNull(Assert.java:211)
at ognl.Java8Test.testGetDeclaredMethods(Java8Test.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
In Thymeleaf there is an Aggregates
class which contains an overloaded avg(...)
method. See the specific class here.
All the different variants of this method look like this:
public BigDecimal avg(final Iterable<? extends Number> target) {...}
public BigDecimal avg(final Number[] target) {...}
public BigDecimal avg(final byte[] target) {...}
public BigDecimal avg(final short[] target) {...}
public BigDecimal avg(final int[] target) {...}
public BigDecimal avg(final long[] target) {...}
public BigDecimal avg(final float[] target) {...}
public BigDecimal avg(final double[] target) {...}
In one of my tests, I create an object using an OGNL expression, like:
nums01 = { 5, 5 }
Which creates a java.util.ArrayList<java.lang.Integer>
for the nums01
variable.
Then I use this variable as an argument to an avg
call in an OGNL expression such as:
#aggregates.avg(nums01)
This worked perfectly until OGNL 3.1.3, and the first version of the overloaded method (the one receiving an Iterable<? extends Number>
) was executed. However, in OGNL 3.1.4 I receive this exception:
java.lang.IllegalArgumentException: Can't decide wich method to use: "public java.math.BigDecimal org.thymeleaf.expression.Aggregates.avg(float[])" or "public java.math.BigDecimal org.thymeleaf.expression.Aggregates.avg(long[])"
at ognl.OgnlRuntime.findBestMethod(OgnlRuntime.java:1427)
at ognl.OgnlRuntime.getAppropriateMethod(OgnlRuntime.java:1283)
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1452)
at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1598)
at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTChain.getValueBody(ASTChain.java:141)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.Ognl.getValue(Ognl.java:494)
at ognl.Ognl.getValue(Ognl.java:458)
Hello OGNL Team,
the latest available ognl library from maven central 3.2.4 will always give a RuntimeException when instantiate OgnlContext will only a Map parameter.
In the source code i found that internally the constructor:
public OgnlContext(MemberAccess memberAccess, ClassResolver classResolver, TypeConverter typeConverter, Map values)
will be called with null values for not given params. This gives a
throw new RuntimeException("MemberAccess implementation must be provided!")
My used library(thymelead) calls this single param constructor and i needed to patch it manually. Is there a default implementation for MemberAccess?
Same problem as here: https://issues.apache.org/jira/browse/OGNL-249
But fix for issue 249 takes into account only interfaces directly implemented by a class and not an interfaces implemented by a parent classes.
I will prepare a pull request with a test case (and maybe a fix also)
Hi,
most of the unit tests are only tested against compiled OGNL expressions. When we do the unit-tests against interpreded and compiled expressions, we see that a lot of unit tests fail:
Results :
Failed tests:
myMap[null](org.ognl.test.InterfaceInheritanceTest)
beans.evenOdd.next(org.ognl.test.InterfaceInheritanceTest)
#root[1](org.ognl.test.ArrayElementsTest)
intValue(org.ognl.test.ArrayElementsTest)
array(org.ognl.test.ArrayElementsTest)
floatValue(org.ognl.test.NumberFormatExceptionTest)
intValue(org.ognl.test.NumberFormatExceptionTest)
intValue(org.ognl.test.NumberFormatExceptionTest)
bigIntValue(org.ognl.test.NumberFormatExceptionTest)
bigIntValue(org.ognl.test.NumberFormatExceptionTest)
bigDecValue(org.ognl.test.NumberFormatExceptionTest)
bigDecValue(org.ognl.test.NumberFormatExceptionTest)
intValue(org.ognl.test.PropertyTest)
booleanValue(org.ognl.test.PropertyTest)
'disableButton(this,"' + map.get('button-testing') + '");clearElement("testFtpMessage")'(org.ognl.test.PropertyTest)
ids (null)(org.ognl.test.GenericsTest)
stringValue(org.ognl.test.MethodWithConversionTest)
values[1](org.ognl.test.IndexedPropertyTest)
property['hoodak'](org.ognl.test.IndexedPropertyTest)
newValue(org.ognl.test.SetterTest)
settableList[0](org.ognl.test.SetterTest)
settableList[2](org.ognl.test.SetterTest)
settableList[$](org.ognl.test.SetterTest)
settableList[^](org.ognl.test.SetterTest)
settableList[|](org.ognl.test.SetterTest)
map.newValue(org.ognl.test.SetterTest)
map.(someMissingKey || newValue)(org.ognl.test.SetterTest)
map.(newValue && aKey)(org.ognl.test.SetterTest)
map[0]="map.newValue", map[0](#this)(org.ognl.test.SetterTest)
openTransitionWin(org.ognl.test.SetterTest)
--1f (1.0)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5f-2F (3.0)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
-1b (-1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
+1b (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
--1b (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
2*2.0b (4.0)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5/2.B (2)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5.0B/2 (2.5)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5+2b (7)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5-2B (3)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5.+2b*3 (11.0)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
(5.+2b)*3 (21.0)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5. & 3 (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5&(3|5^3) (5)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
-1h (-1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
+1H (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
--1h (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
2h*2 (4)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5/2h (2)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h+2 (7)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5-2h (3)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5+2H*3 (11)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
(5+2H)*3 (21)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
~1h (-2)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h%2 (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h<<2 (20)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h>>2 (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h>>1+1 (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
-5h>>>2 (-2)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5.b & 3 (1)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h ^3 (6)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5h&3|5^3 (7)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
5H&(3|5^3) (5)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
1 band 0 (0)(org.ognl.test.ArithmeticAndLogicalOperatorsTest)
attribute["bar"](org.ognl.test.ObjectIndexedPropertyTest)
1234L (1234)(org.ognl.test.ConstantTest)
12.34f (12.34)(org.ognl.test.ConstantTest)
intValue(org.ognl.test.SetterWithConversionTest)
intValue(org.ognl.test.SetterWithConversionTest)
intValue(org.ognl.test.SetterWithConversionTest)
stringValue(org.ognl.test.SetterWithConversionTest)
stringValue(org.ognl.test.SetterWithConversionTest)
anotherStringValue(org.ognl.test.SetterWithConversionTest)
anotherStringValue(org.ognl.test.SetterWithConversionTest)
anotherIntValue(org.ognl.test.SetterWithConversionTest)
anotherIntValue(org.ognl.test.SetterWithConversionTest)
tab.searchCriteriaSelections[index1][index2](org.ognl.test.IndexAccessTest)
map['bar'].value(org.ognl.test.IndexAccessTest)
thing["x"].val(org.ognl.test.IndexAccessTest)
messages.format('ShowAllCount', {one}) (foo)(org.ognl.test.MethodTest)
messages.format('ShowAllCount', {one, two}) (foo)(org.ognl.test.MethodTest)
floatValue(org.ognl.test.PrimitiveNullHandlingTest)
intValue(org.ognl.test.PrimitiveNullHandlingTest)
booleanValue(org.ognl.test.PrimitiveNullHandlingTest)
booleanValue(org.ognl.test.PrimitiveNullHandlingTest)
Tests in error:
getValues(org.ognl.test.IndexedPropertyTest)
testMethods.getBean('TestBean') (NamedBean: TestBean)(org.ognl.test.MethodTest)
testMethods.testProperty (Hello World!)(org.ognl.test.MethodTest)
Tests run: 735, Failures: 85, Errors: 3, Skipped: 0
diff --git a/src/test/java/org/ognl/test/OgnlTestCase.java b/src/test/java/org/ognl/test/OgnlTestCase.java
index 5639350..dac2238 100644
--- a/src/test/java/org/ognl/test/OgnlTestCase.java
+++ b/src/test/java/org/ognl/test/OgnlTestCase.java
@@ -194,6 +194,25 @@ public class OgnlTestCase extends TestCase {
try {
SimpleNode expr;
+ if (_compileExpressions) {
+ // round 1 - parse only
+ _compileExpressions = false;
+ testedResult = _expectedResult;
+ expr = getExpression();
+
+ assertEquals(_expectedResult, Ognl.getValue(expr, _context, _root));
+
+ if (hasSetValue)
+ {
+ testedResult = hasExpectedAfterSetResult ? expectedAfterSetResult : setValue;
+ Ognl.setValue(expr, _context, _root, setValue);
+
+ assertEquals(testedResult, Ognl.getValue(expr, _context, _root));
+ }
+ // round two - compile expressions
+ _compileExpressions = true;
+ }
+
testedResult = _expectedResult;
expr = getExpression();
Might be a thing for OGNL-4 ?
When the argument memberAccess passed by the overloaded method above is null, a runtime exception will occur
@Deprecated
public static Map addDefaultContext(Object root, Map context)
{
return addDefaultContext(root, null, null, null, context);
}
test code:
public static void main(String[] args) throws OgnlException {
User root = new User();
root.setId(19612);
root.setName("sakura");
Map context = new HashMap();
context.put("who", "Who am i");
String who1 = (String) Ognl.getValue("#who", context, root);
System.out.println(who1);
}
error message:
Exception in thread "main" java.lang.RuntimeException: MemberAccess implementation must be provided!
at ognl.OgnlContext.<init>(OgnlContext.java:140)
In current release 3.2.11 and master the deprecated constructor public OgnlContext(Map values)
in line 117 is unusable and should be removed immediately (or fixed). Currently it will always leads to a NullPointerException in line 170 of the class. To my understanding functionality marked with 'deprecated' should no longer be used (as it will be removed in a future release), but should not be unusable 'by concept'.
Security Manager still does not work correctly with OGNL. The only workaround appears to be OgnlRuntime.setSecurityManager(null),
We get
java.lang.IllegalAccessException: Method [public java.lang.String com.opensymphony.xwork2.ActionSupport.execute() throws java.lang.Exception] cannot be accessed.
Can you please either fix Ognl's ability to work with security manager , or provide an example working policy file
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.