package com.fasterxml.jackson.dataformat.javaprop.util;
import java.util.*;
Value in an ordered tree presentation built from an arbitrarily ordered
set of flat input values. Since either index- OR name-based access is to
be supported (similar to, say, Javascript objects) -- but only one, not both --
storage is bit of a hybrid. In addition, branches may also have values.
So, code does bit coercion as necessary, trying to maintain something
consistent and usable at all times, without failure.
/**
* Value in an ordered tree presentation built from an arbitrarily ordered
* set of flat input values. Since either index- OR name-based access is to
* be supported (similar to, say, Javascript objects) -- but only one, not both --
* storage is bit of a hybrid. In addition, branches may also have values.
* So, code does bit coercion as necessary, trying to maintain something
* consistent and usable at all times, without failure.
*/
public class JPropNode
{
Value for the path, for leaf nodes; usually null for branches.
If both children and value exists, typically need to construct
bogus value with empty String key.
/**
* Value for the path, for leaf nodes; usually null for branches.
* If both children and value exists, typically need to construct
* bogus value with empty String key.
*/
protected String _value;
Child entries with integral number index, if any.
/**
* Child entries with integral number index, if any.
*/
protected TreeMap<Integer, JPropNode> _byIndex;
Child entries accessed with String property name, if any.
/**
* Child entries accessed with String property name, if any.
*/
protected Map<String, JPropNode> _byName;
protected boolean _hasContents = false;
public JPropNode setValue(String v) {
// should we care about overwrite?
_value = v;
return this;
}
public JPropNode addByIndex(int index) {
// if we already have named entries, coerce into name
if (_byName != null) {
return addByName(String.valueOf(index));
}
_hasContents = true;
if (_byIndex == null) {
_byIndex = new TreeMap<>();
}
Integer key = Integer.valueOf(index);
JPropNode n = _byIndex.get(key);
if (n == null) {
n = new JPropNode();
_byIndex.put(key, n);
}
return n;
}
public JPropNode addByName(String name) {
// if former index entries, first coerce them
_hasContents = true;
if (_byIndex != null) {
if (_byName == null) {
_byName = new LinkedHashMap<>();
}
for (Map.Entry<Integer, JPropNode> entry : _byIndex.entrySet()) {
_byName.put(entry.getKey().toString(), entry.getValue());
}
_byIndex = null;
}
if (_byName == null) {
_byName = new LinkedHashMap<>();
} else {
JPropNode old = _byName.get(name);
if (old != null) {
return old;
}
}
JPropNode result = new JPropNode();
_byName.put(name, result);
return result;
}
public boolean isLeaf() {
return !_hasContents && (_value != null);
}
public boolean isArray() {
return _byIndex != null;
}
public String getValue() {
return _value;
}
public Iterator<JPropNode> arrayContents() {
// should never be called if `_byIndex` is null, hence no checks
return _byIndex.values().iterator();
}
Child entries accessed with String property name, if any.
/**
* Child entries accessed with String property name, if any.
*/
public Iterator<Map.Entry<String, JPropNode>> objectContents() {
if (_byName == null) { // only value, most likely
return Collections.emptyIterator();
}
return _byName.entrySet().iterator();
}
Helper method, mostly for debugging/testing, to convert structure contained
into simple List/Map/String equivalent.
/**
* Helper method, mostly for debugging/testing, to convert structure contained
* into simple List/Map/String equivalent.
*/
public Object asRaw() {
if (isArray()) {
List<Object> result = new ArrayList<>();
if (_value != null) {
result.add(_value);
}
for (JPropNode v : _byIndex.values()) {
result.add(v.asRaw());
}
return result;
}
if (_byName != null) {
Map<String,Object> result = new LinkedHashMap<>();
if (_value != null) {
result.put("", _value);
}
for (Map.Entry<String, JPropNode> entry : _byName.entrySet()) {
result.put(entry.getKey(), entry.getValue().asRaw());
}
return result;
}
return _value;
}
}