Skip to content

Instantly share code, notes, and snippets.

@harawata
Last active November 2, 2019 08:46
Show Gist options
  • Save harawata/ba122c27106802b34f84bcb8a6566932 to your computer and use it in GitHub Desktop.
Save harawata/ba122c27106802b34f84bcb8a6566932 to your computer and use it in GitHub Desktop.
Demo app trying to reproduce https://github.com/mybatis/mybatis-3/issues/1648 but to no avail.
import ognl.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.*;
public class ConcurrentGetValue {
public static void main(String[] args) {
int size = Integer.valueOf(args[0]);
final Person p = new Person();
final Map<String, Object> map = new HashMap<String, Object>();
map.put("person", p);
for (int i = 0; i < size; i++) {
new MyThread(map).start();
}
}
public static class MyThread extends Thread {
private static final OgnlMemberAccess MEMBER_ACCESS = new OgnlMemberAccess();
private static final OgnlClassResolver CLASS_RESOLVER = new OgnlClassResolver();
private static final Map<String, Object> expressionCache = new ConcurrentHashMap<>();
private final Map<String, Object> map;
private final OgnlContext ctxt;
public MyThread(Map<String, Object> map) {
this.map = map;
this.ctxt = (OgnlContext)Ognl.createDefaultContext(null, MEMBER_ACCESS, CLASS_RESOLVER, null);
}
public void run() {
try {
Boolean result = (Boolean)Ognl.getValue("person.pet.id != null", ctxt, map);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static interface HasId<T> {
T getId();
}
public static class Person implements HasId<Integer> {
private Pet pet = new Pet();
public Integer getId() {
return Integer.valueOf(123);
}
public Pet getPet() {
return pet;
}
}
public static class Pet {
public Integer getId() {
return Integer.valueOf(123);
}
}
public static class OgnlClassResolver extends DefaultClassResolver {
@Override
protected Class toClassForName(String className) throws ClassNotFoundException {
return Class.forName(className);
}
}
public static class OgnlMemberAccess implements MemberAccess {
private final boolean canControlMemberAccessible;
OgnlMemberAccess() {
this.canControlMemberAccessible = canControlMemberAccessible();
}
@Override
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.FALSE;
accessible.setAccessible(true);
}
}
return result;
}
@Override
public void restore(Map context, Object target, Member member, String propertyName,
Object state) {
if (state != null) {
((AccessibleObject) member).setAccessible((Boolean) state);
}
}
@Override
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
return canControlMemberAccessible;
}
private static boolean canControlMemberAccessible() {
try {
SecurityManager securityManager = System.getSecurityManager();
if (null != securityManager) {
securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
} catch (SecurityException e) {
return false;
}
return true;
}
}
}
#!/bin/sh
java -version
# compile
javac ConcurrentGetValue.java -cp ognl-3.2.10.jar
# run rounds
for i in {1..10}
do
java -cp ognl-3.2.10.jar:javassist-3.24.1-GA.jar:. ConcurrentGetValue 50
done
@harawata
Copy link
Author

I could reproduce the exception on Java version 1.6.0_65 and 1.7.0_80.
NoSuchPropertyException is thrown once in 10-20 execution on my 3 years old MacBook Pro.

As the underlying JDK bug was fixed in 8u20 and 8u25, the exception won't be thrown in newer versions.

@harawata
Copy link
Author

harawata commented Nov 2, 2019

Updated to revision 3 trying to reproduce mybatis/mybatis-3#1648 but to no avail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment