package org.jboss.processFlow.console.binding.spring; import java.util.HashMap; import java.util.Map; import org.jboss.processFlow.console.binding.AbstractDataBinder; import org.springframework.beans.MutablePropertyValues; import org.springframework.format.datetime.joda.JodaDateTimeFormatAnnotationFormatterFactory; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.validation.DataBinder; /** * DOCME * * @author tanxu * @date Feb 14, 2012 * @since */ public class SpringDataBinder extends AbstractDataBinder { private DefaultFormattingConversionService conversionService; public SpringDataBinder() { super(); conversionService = new DefaultFormattingConversionService(); // set the conversion service to convert the date conversionService.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory()); } @Override protected Map<String, Object> renderContextIfNeeded(Object target, Map<String, Object> valueContext) { HashMap<String, Object> newContext = new HashMap<String, Object>(valueContext.size()); if (target instanceof InternalMapBean) { for (Map.Entry<String, Object> entry : valueContext.entrySet()) { String key = entry.getKey(); if (!isNavigatiableProperty(key)) continue; // filter the interested context according to the property // otherwise, we might get the error if non-used context values exists: // "Property referenced in indexed property path is neither an array nor a List nor a Map" boolean match = false; for (String property : ((InternalMapBean) target).getResultsMap().keySet()) { if (key.startsWith(property)) { match = true; break; } } if (match == false) continue; String newProperty = "resultsMap['"; // "resultsMap" is the filed name of InternalMapBean // deal with tokens contain nagivator sign int rightBracketIdx = key.indexOf(']'); if (rightBracketIdx > 0) { // deal with indexed property path String prop = key.substring(0, rightBracketIdx); int leftBracketIdx = prop.indexOf('['); if (leftBracketIdx > 0) { newProperty = newProperty + prop.substring(0, leftBracketIdx) + "']" + prop.substring(leftBracketIdx) + key.substring(rightBracketIdx); } else { newProperty = newProperty + prop.substring(0, leftBracketIdx) + "']" + key.substring(rightBracketIdx); } } else { int dotIdx = key.indexOf('.'); // deal with normal property path if (dotIdx > 0) { newProperty = newProperty + key.substring(0, dotIdx) + "']" + key.substring(dotIdx); } else { newProperty = newProperty + key + "']"; } } newContext.put(newProperty, entry.getValue()); } } else { newContext.putAll(valueContext); } return newContext; } @Override protected Object renderTargetIfNeeded(Object target, Map<String, Object> valueContext) { if (target instanceof Map) { InternalMapBean bean = new InternalMapBean(); bean.setResultsMap((Map) target); return bean; } return target; } @Override protected Object doConvert(Class targetType, Object source) { return conversionService.convert(source, targetType); } @Override protected Map<String, Object> doBind(Object target, Map<String, Object> context) throws Exception { MutablePropertyValues values = new MutablePropertyValues(); for (Map.Entry<String, Object> entry : context.entrySet()) { values.addPropertyValue(entry.getKey(), entry.getValue()); } DataBinder binder = new DataBinder(target); binder.setConversionService(conversionService); binder.bind(values); Map newValues = null; if (target instanceof InternalMapBean) { newValues = ((InternalMapBean) target).getResultsMap(); } else { newValues = getProperties(target); } return newValues; } }