package cn.jimmyshi.beanquery.selectors; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; /** * A selector that sorted some of the result key-value pairs into a map which has the same prefix ended with ".". * For example, * <ul> * <li>Without this: result of select("a1, a2.b, a2.c") is a list of map with 3 keys: a1, a2.b, a2.c.</li> * <li>With this, result of select("a1, a2.b, a2.c") will be a list of map with 2 keys: a1, a2. and the value of a2 is a map with keys: b and c</li> * </ul> * * This class is created to fulfill requirement: https://github.com/Jimmy-Shi/bean-query/issues/9 * */ public class NestedKeyValueMapSelector extends KeyValueMapSelector { private KeyValueMapSelector selector; public NestedKeyValueMapSelector(KeyValueMapSelector sourceSelector) { this.selector=sourceSelector; } @Override protected Map<String, Object> doSelect(Object item) { Map<String, Object> originalResult = this.selector.select(item); if(MapUtils.isEmpty(originalResult)){ return originalResult; } Map<String,Object> result=new LinkedHashMap<String, Object>(); for (Entry<String, Object> originalItem : originalResult.entrySet()) { String key = originalItem.getKey(); Object value = originalItem.getValue(); if(StringUtils.isBlank(key) || (!key.contains("."))){ result.put(key, value); continue; } addNestedKeyValue(key, value, result); } return result; } private void addNestedKeyValue(String key,Object value, Map<String,Object> container){ if(!key.contains(".")){ container.put(key, value); return; } String firstKey=StringUtils.substringBefore(key, "."); Map<String,Object> subContainer=new LinkedHashMap<String, Object>(); if(container.containsKey(firstKey)){ Object originalValue = container.get(firstKey); if(subContainer.getClass().isAssignableFrom(originalValue.getClass())){ subContainer=(Map<String, Object>) originalValue; }else{ subContainer.put("", originalValue); container.put(firstKey, subContainer); } }else{ container.put(firstKey, subContainer); } addNestedKeyValue(StringUtils.substringAfter(key, "."), value, subContainer); } }