package com.jsoniter.any; import com.jsoniter.ValueType; import com.jsoniter.output.JsonStream; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; class MapWrapperAny extends Any { private final Map val; private Map<String, Any> cache; public MapWrapperAny(Map val) { this.val = val; } @Override public ValueType valueType() { return ValueType.OBJECT; } @Override public Object object() { fillCache(); return cache; } @Override public boolean toBoolean() { return size() != 0; } @Override public int toInt() { return size(); } @Override public long toLong() { return size(); } @Override public float toFloat() { return size(); } @Override public double toDouble() { return size(); } @Override public String toString() { if (cache == null) { return JsonStream.serialize(val); } else { fillCache(); return JsonStream.serialize(cache); } } @Override public void writeTo(JsonStream stream) throws IOException { if (cache == null) { stream.writeVal(val); } else { fillCache(); stream.writeVal(cache); } } @Override public int size() { return val.size(); } @Override public Any get(Object key) { return fillCacheUntil(key); } @Override public Any get(Object[] keys, int idx) { if (idx == keys.length) { return this; } Object key = keys[idx]; if (isWildcard(key)) { fillCache(); HashMap<String, Any> result = new HashMap<String, Any>(); for (Map.Entry<String, Any> entry : cache.entrySet()) { Any mapped = entry.getValue().get(keys, idx + 1); if (mapped.valueType() != ValueType.INVALID) { result.put(entry.getKey(), mapped); } } return Any.rewrap(result); } Any child = fillCacheUntil(key); if (child == null) { return new NotFoundAny(keys, idx, object()); } return child.get(keys, idx + 1); } @Override public EntryIterator entries() { return new WrapperIterator(); } private Any fillCacheUntil(Object target) { if (cache == null) { cache = new HashMap<String, Any>(); } Any element = cache.get(target); if (element != null) { return element; } Set<Map.Entry<String, Object>> entries = val.entrySet(); int targetHashcode = target.hashCode(); for (Map.Entry<String, Object> entry : entries) { String key = entry.getKey(); if (cache.containsKey(key)) { continue; } element = Any.wrap(entry.getValue()); cache.put(key, element); if (targetHashcode == key.hashCode() && target.equals(key)) { return element; } } return new NotFoundAny(target, val); } private void fillCache() { if (cache == null) { cache = new HashMap<String, Any>(); } Set<Map.Entry<String, Object>> entries = val.entrySet(); for (Map.Entry<String, Object> entry : entries) { String key = entry.getKey(); if (cache.containsKey(key)) { continue; } Any element = Any.wrap(entry.getValue()); cache.put(key, element); } } private class WrapperIterator implements EntryIterator { private final Iterator<Map.Entry<String, Object>> iter; private String key; private Any value; private WrapperIterator() { Set<Map.Entry<String, Object>> entries = val.entrySet(); iter = entries.iterator(); } @Override public boolean next() { if (cache == null) { cache = new HashMap<String, Any>(); } if (!iter.hasNext()) { return false; } Map.Entry<String, Object> entry = iter.next(); key = entry.getKey(); value = cache.get(key); if (value == null) { value = Any.wrap(entry.getValue()); cache.put(key, value); } return true; } @Override public String key() { return key; } @Override public Any value() { return value; } } }