package net.techreadiness.ognl;
import java.util.Map;
import ognl.OgnlContext;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import com.google.common.collect.Multimap;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
public class MultimapPropertyAccessor implements PropertyAccessor {
private XWorkConverter xworkConverter;
private ObjectTypeDeterminer objectTypeDeterminer;
@Inject
public void setXWorkConverter(XWorkConverter conv) {
xworkConverter = conv;
}
@Inject
public void setObjectTypeDeterminer(ObjectTypeDeterminer ot) {
objectTypeDeterminer = ot;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
ReflectionContextState.updateCurrentPropertyPath(context, name);
Object result = null;
Multimap multimap = (Multimap) target;
try {
result = multimap.get(name);
} catch (RuntimeException ex) {
if (!(ex.getCause() instanceof ClassCastException)) {
throw ex;
}
}
if (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);
if (lastClass == null || lastProperty == null) {
return multimap.get(name);
}
Class keyClass = objectTypeDeterminer.getKeyClass(lastClass, lastProperty);
if (keyClass == null) {
keyClass = java.lang.String.class;
}
Object key = getKey(context, name);
result = multimap.get(key);
}
return result;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
Object key = getKey(context, name);
Multimap multimap = (Multimap) target;
if (value.getClass().isArray()) {
Object[] values = (Object[]) value;
for (Object o : values) {
Object value2 = getValue(context, o);
if (value2 != null) {
multimap.put(key, value2);
}
}
} else {
Object value2 = getValue(context, value);
if (value2 != null) {
multimap.put(key, value2);
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object getValue(Map context, Object value) {
if (value == null || "".equals(value)) {
return null;
}
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);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
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;
}
Class keyClass = objectTypeDeterminer.getKeyClass(lastClass, lastProperty);
if (keyClass == null) {
keyClass = java.lang.String.class;
}
return xworkConverter.convertValue(context, name, keyClass);
}
@Override
public String getSourceAccessor(OgnlContext context, Object target, Object index) {
// TODO Auto-generated method stub
return null;
}
@Override
public String getSourceSetter(OgnlContext context, Object target, Object index) {
// TODO Auto-generated method stub
return null;
}
}