Skip to content

Commit e1ccbce

Browse files
author
Igor Polevoy
committed
#217 Improve TemplateParser performance
1 parent 0f38f21 commit e1ccbce

File tree

2 files changed

+93
-30
lines changed

2 files changed

+93
-30
lines changed

javalite-templator/src/main/java/org/javalite/templator/AbstractTag.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,6 @@ public boolean marchArgumentEnd(String template, int index) {
190190
protected final Object getValue(Object obj, String propertyName) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
191191

192192

193-
//quick hack:
194-
if (methodCache.get() == null) {
195-
methodCache.set(new HashMap<String, Method>());
196-
}
197-
198193
Object val = null;
199194

200195
//try map
@@ -238,6 +233,12 @@ protected final Object getValue(Object obj, String propertyName) throws Invocati
238233

239234
private Object executeMethod(Object obj, String methodName, String propertyName) throws InvocationTargetException, IllegalAccessException {
240235

236+
//quick hack:
237+
if (methodCache.get() == null) {
238+
methodCache.set(new HashMap<String, Method>());
239+
}
240+
241+
241242
String key = obj.getClass().getName() + "#" + methodName;
242243
Method m = null;
243244

javalite-templator/src/main/java/org/javalite/templator/template_parser/ChainedIds.java

Lines changed: 87 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import org.javalite.templator.TemplateException;
44

5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.InvocationTargetException;
7+
import java.lang.reflect.Method;
8+
import java.util.HashMap;
59
import java.util.List;
610
import java.util.Map;
711
import static org.javalite.common.Inflector.*;
@@ -18,40 +22,98 @@ class ChainedIds {
1822
this.ids = ids;
1923
}
2024

21-
private Object valueOf(Object obj, String id) {
22-
try {
23-
if (id.endsWith("()")) {
24-
return obj.getClass().getMethod(id.substring(0, id.length() - 2)).invoke(obj);
25+
private Object valueOf(Object obj, String propertyName) throws InvocationTargetException, IllegalAccessException {
26+
27+
if (propertyName.endsWith("()")) {
28+
return executeMethod(obj, propertyName.substring(0, propertyName.length() - 2), null);
29+
2530
}
26-
} catch (Exception e) {
27-
throw new TemplateException(e);
28-
}
31+
32+
Object val = null;
33+
34+
//try map
2935
if (obj instanceof Map) {
30-
return ((Map) obj).get(id);
36+
Map objectMap = (Map) obj;
37+
return objectMap.get(propertyName);
38+
}
39+
40+
if (val == null) {
41+
//try properties
42+
val = executeMethod(obj, "get" + capitalize(propertyName), null);
43+
if(val != null)
44+
return val;
3145
}
32-
try {
33-
// try generic get method
34-
return obj.getClass().getMethod("get", String.class).invoke(obj, id);
35-
} catch (Exception e) {
46+
47+
48+
//try generic get method
49+
if (val == null) {
50+
val = executeMethod(obj, "get", propertyName);
51+
if(val != null)
52+
return val;
53+
}
54+
55+
56+
if (val == null) {
57+
// try public fields
3658
try {
37-
// try javabean property
38-
return obj.getClass().getMethod("get" + capitalize(id)).invoke(obj);
39-
} catch (Exception e1) {
40-
// try public field
41-
try {
42-
return obj.getClass().getDeclaredField(id).get(obj);
43-
} catch (Exception e2) {
44-
}
59+
//TODO: optimize the same as methods.
60+
Field f = obj.getClass().getDeclaredField(propertyName);
61+
val = f.get(obj);
62+
if(val != null)
63+
return val;
64+
65+
} catch (NoSuchFieldException ignore) {
66+
} catch (IllegalAccessException ignore) {
4567
}
4668
}
47-
return null;
69+
70+
return val;
71+
}
72+
73+
private ThreadLocal<Map<String, Method>> methodCache = new ThreadLocal<Map<String, Method>>();
74+
75+
private Object executeMethod(Object obj, String methodName, String propertyName) throws InvocationTargetException, IllegalAccessException {
76+
77+
//quick hack:
78+
if (methodCache.get() == null) {
79+
methodCache.set(new HashMap<String, Method>());
80+
}
81+
82+
83+
String key = obj.getClass().getName() + "#" + methodName;
84+
Method m = null;
85+
86+
if (!methodCache.get().containsKey(key)) {
87+
try {
88+
m = propertyName == null ? obj.getClass().getMethod(methodName) : obj.getClass().getMethod(methodName, String.class);
89+
} catch (NoSuchMethodException e) {}
90+
91+
// if we find a method, we will cache it, if not we will cache null
92+
methodCache.get().put(key, m);
93+
} else if (methodCache.get().get(key) == null) { // we did not find this method last time!
94+
return null;
95+
} else {
96+
m = methodCache.get().get(key); // method found!
97+
}
98+
99+
if(m != null){
100+
return propertyName == null ? m.invoke(obj) : m.invoke(obj, propertyName);
101+
}else{
102+
return null;
103+
}
48104
}
49105

106+
50107
Object valueFrom(Map values) {
51-
Object obj = values.get(firstId);
52-
for (String id : ids) {
53-
obj = valueOf(obj, id);
108+
try{
109+
Object obj = values.get(firstId);
110+
for (String id : ids) {
111+
obj = valueOf(obj, id);
112+
}
113+
return obj;
114+
}catch(Exception e){
115+
throw new TemplateException(e);
54116
}
55-
return obj;
117+
56118
}
57119
}

0 commit comments

Comments
 (0)