All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.nhs.ciao.docs.parser.PropertySelector Maven / Gradle / Ivy

The newest version!
package uk.nhs.ciao.docs.parser;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import uk.nhs.ciao.util.SimpleEntry;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.ObjectArrays;

/**
 * Selects a property (or properties) from a dynamic map structure.
 * 

* Supported syntax is: *

    *
  • .{string} - matches key in map *
  • [{integer}] - matches index in list *
  • .* - matches any key in map *
  • [*] - matches any index in list *
*

* Some examples: *

    *
  • authors[1] *
  • author.firstName *
  • author.* *
  • authors[*] *
  • authors[*].* *
*/ public final class PropertySelector { /** * Selects the root of a properties map */ private static final PropertySelector ROOT = new PropertySelector(new Object[0]); private final Object[] segments; private final boolean multi; private int hash; /** * Returns a selector matching the specified path */ public static PropertySelector valueOf(final String path) { final boolean allowWildcards = true; return Strings.isNullOrEmpty(path) ? ROOT : new PropertySelector(PropertyPath.parse(path, allowWildcards)); } PropertySelector(final Object[] segments) { this.segments = segments; this.multi = PropertyPath.containsWildcard(segments); } /** * Tests if this is the root selector */ public boolean isRoot() { return segments.length == 0; } /** * Tests if this selector may select multiple matches * (i.e. contains a wildcard) */ public boolean isMulti() { return multi; } /** * Returns the PropertyName equivalent to this selector if a single name is identified or * null if the path contains wildcards */ public PropertyName toPropertyName() { return multi ? null : new PropertyName(Arrays.copyOf(segments, segments.length)); } /** * Returns the string path associated with this selector */ public String getPath() { return PropertyPath.toString(segments); } /** * Returns the parent of this selector if it is not a root */ public PropertySelector getParent() { return isRoot() ? null : new PropertySelector(Arrays.copyOf(segments, segments.length - 1)); } /** * Returns the child selector associated with this selector and the specified * appended path segments */ public PropertySelector getChild(final String childPath) { final boolean allowWildcards = true; final Object[] childSegments = PropertyPath.parse(childPath, allowWildcards); Preconditions.checkArgument(childSegments.length > 0, "childPath must be provided"); return new PropertySelector(ObjectArrays.concat(segments, childSegments, Object.class)); } /** * Selects the first matching property key/value pairs from the dynamic map *

* The entry key is encoded as a matching path */ public Entry select(final Map properties) { return select(Object.class, properties); } /** * Selects the first matching property value from the dynamic map */ public Object selectValue(final Map properties) { return selectValue(Object.class, properties); } /** * Selects the first matching property key/value pairs from the dynamic map *

* The entry key is encoded as a matching path * * @param type The type of objects matched - any objects matching the path selector but of * the wrong type are ignored */ public Entry select(final Class type, final Map properties) { final Entry entry = PropertyPath.getEntry(type, properties, segments); return entry == null ? null : SimpleEntry.valueOf(PropertyPath.toString(entry.getKey()), entry.getValue()); } /** * Selects the first matching property value from the dynamic map * * @param type The type of objects matched - any objects matching the path selector but of * the wrong type are ignored */ public T selectValue(final Class type, final Map properties) { return PropertyPath.getValue(type, properties, segments); } /** * Selects all matching property key/value pairs from the dynamic map *

* The entry key is encoded as a matching path */ public Map selectAll(final Map properties) { return selectAll(Object.class, properties); } /** * Selects all matching property values from the dynamic map */ public List selectAllValues(final Map properties) { return selectAllValues(Object.class, properties); } /** * Selects all matching property key/value pairs from the dynamic map *

* The entry key is encoded as a matching path * * @param type The type of objects matched - any objects matching the path selector but of * the wrong type are ignored */ public Map selectAll(final Class type, final Map properties) { final Map results = Maps.newLinkedHashMap(); for (final Entry entry: PropertyPath.findAll(type, properties, segments)) { results.put(PropertyPath.toString(entry.getKey()), entry.getValue()); } return results; } /** * Selects all matching property values from the dynamic map * * @param type The type of objects matched - any objects matching the path selector but of * the wrong type are ignored */ public List selectAllValues(final Class type, final Map properties) { final List results = Lists.newArrayList(); for (final Entry entry: PropertyPath.findAll(type, properties, segments)) { results.add(entry.getValue()); } return results; } @Override public int hashCode() { int result = hash; if (result == 0) { result = Arrays.hashCode(segments); hash = result; // safe to publish without volatile } return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj == null || getClass() != obj.getClass()) { return false; } final PropertySelector other = (PropertySelector) obj; return Arrays.equals(segments, other.segments); } @Override public String toString() { return Arrays.toString(segments); } }