blob: 4ee6f8e1fae65b037aba87a58b3a0a13a2e71597 [file] [log] [blame]
package org.apache.struts2.uelplugin.elresolvers;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import javax.el.ELContext;
import java.util.Map;
import java.util.List;
import java.util.WeakHashMap;
public class XWorkMapELResolver extends AbstractResolver {
private final Map<Key, Class> keyClassCache = new WeakHashMap<Key, Class>();
public XWorkMapELResolver(Container container) {
super(container);
}
public Object getValue(ELContext elContext, Object target, Object property) {
Map<String, Object> context = (Map) elContext.getContext(AccessorsContextKey.class);
if (target != null && property != null && target instanceof Map) {
Object result = null;
//find the key class and convert the name to that class
Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED);
Class keyClass = objectTypeDeterminer.getKeyClass(lastClass, lastProperty);
if (keyClass == null)
keyClass = String.class;
Object key = getKey(context, property);
Map map = (Map) target;
result = map.get(key);
if (result == null &&
context.get(ReflectionContextState.CREATE_NULL_OBJECTS) != null
&& objectTypeDeterminer.shouldCreateIfNew(lastClass, lastProperty, target, null, false)) {
Class valueClass = objectTypeDeterminer.getElementClass(lastClass, lastProperty, key);
try {
result = objectFactory.buildBean(valueClass, context);
map.put(key, result);
} catch (Exception exc) {
}
}
elContext.setPropertyResolved(true);
return result;
}
return null;
}
private Object getKey(Map context, Object name) {
Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED);
if (lastClass == null || lastProperty == null) {
// return java.lang.String.class;
// commented out the above -- it makes absolutely no sense for when setting basic maps!
return name;
}
Key key = new Key(lastClass, lastProperty);
//lookup in the cache first
Class keyClass = keyClassCache.get(key);
if (keyClass == null) {
keyClass = objectTypeDeterminer.getKeyClass(lastClass, lastProperty);
if (keyClass != null)
keyClassCache.put(key, keyClass);
}
if (keyClass == null) {
keyClass = String.class;
keyClassCache.put(key, String.class);
}
return xworkConverter.convertValue(context, name, keyClass);
}
public void setValue(ELContext elContext, Object target, Object property, Object value) {
Map<String, Object> context = (Map) elContext.getContext(AccessorsContextKey.class);
if (target != null && property != null && target instanceof Map) {
Object key = getKey(context, property);
Map map = (Map) target;
map.put(key, getValue(context, value));
}
}
private Object getValue(Map context, Object value) {
Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED);
if (lastClass == null || lastProperty == null) {
return value;
}
Class elementClass = objectTypeDeterminer.getElementClass(lastClass, lastProperty, null);
if (elementClass == null) {
return value; // nothing is specified, we assume it will be the value passed in.
}
return xworkConverter.convertValue(context, value, elementClass);
}
}
class Key {
Class clazz;
String property;
Key(Class clazz, String property) {
this.clazz = clazz;
this.property = property;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (clazz != null ? !clazz.equals(key.clazz) : key.clazz != null) return false;
if (property != null ? !property.equals(key.property) : key.property != null) return false;
return true;
}
public int hashCode() {
int result = clazz != null ? clazz.hashCode() : 0;
result = 31 * result + (property != null ? property.hashCode() : 0);
return result;
}
}