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

com.rt.storage.api.client.util.DataMap Maven / Gradle / Ivy

package com.rt.storage.api.client.util;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Map that uses {@link ClassInfo} to parse the key/value pairs into a map for use in {@link
 * Data#mapOf(Object)}.
 *
 * @author Yaniv Inbar
 */
final class DataMap extends AbstractMap {

  // TODO(yanivi): implement more methods for faster implementation!

  /** Object being reflected. */
  final Object object;

  /** Object's class info. */
  final ClassInfo classInfo;

  /** @param object object being reflected */
  DataMap(Object object, boolean ignoreCase) {
    this.object = object;
    classInfo = ClassInfo.of(object.getClass(), ignoreCase);
  }

  @Override
  public EntrySet entrySet() {
    return new EntrySet();
  }

  @Override
  public boolean containsKey(Object key) {
    return get(key) != null;
  }

  @Override
  public Object get(Object key) {
    if (!(key instanceof String)) {
      return null;
    }
    FieldInfo fieldInfo = classInfo.getFieldInfo((String) key);
    if (fieldInfo == null) {
      return null;
    }
    return fieldInfo.getValue(object);
  }

  @Override
  public Object put(String key, Object value) {
    FieldInfo fieldInfo = classInfo.getFieldInfo(key);
    Preconditions.checkNotNull(fieldInfo, "no field of key " + key);
    Object oldValue = fieldInfo.getValue(object);
    fieldInfo.setValue(object, Preconditions.checkNotNull(value));
    return oldValue;
  }

  /** Set of object data key/value map entries. */
  final class EntrySet extends AbstractSet> {

    @Override
    public EntryIterator iterator() {
      return new EntryIterator();
    }

    @Override
    public int size() {
      int result = 0;
      for (String name : classInfo.names) {
        if (classInfo.getFieldInfo(name).getValue(object) != null) {
          result++;
        }
      }
      return result;
    }

    @Override
    public void clear() {
      for (String name : classInfo.names) {
        classInfo.getFieldInfo(name).setValue(object, null);
      }
    }

    @Override
    public boolean isEmpty() {
      for (String name : classInfo.names) {
        if (classInfo.getFieldInfo(name).getValue(object) != null) {
          return false;
        }
      }
      return true;
    }
  }

  /** Iterator over the object data key/value map entries. */
  final class EntryIterator implements Iterator> {

    /**
     * Next index into key names array computed in {@link #hasNext()} or {@code -1} before {@link
     * #hasNext()} has been called.
     */
    private int nextKeyIndex = -1;

    /**
     * Next field info computed in {@link #hasNext()} or {@code null} before {@link #hasNext()} has
     * been called since the last {@link #next()}.
     */
    private FieldInfo nextFieldInfo;

    /**
     * Next field value computed in {@link #hasNext()} or {@code null} before {@link #hasNext()} has
     * been called since the last {@link #next()}.
     */
    private Object nextFieldValue;

    /** Whether {@link #remove()} has been called since last time {@link #next()} was called. */
    private boolean isRemoved;

    /** Whether the next field has been computed. */
    private boolean isComputed;

    /**
     * Current field info found by {@link #next()} or {@code null} before {@link #next()} has been
     * called.
     */
    private FieldInfo currentFieldInfo;

    public boolean hasNext() {
      if (!isComputed) {
        isComputed = true;
        nextFieldValue = null;
        while (nextFieldValue == null && ++nextKeyIndex < classInfo.names.size()) {
          nextFieldInfo = classInfo.getFieldInfo(classInfo.names.get(nextKeyIndex));
          nextFieldValue = nextFieldInfo.getValue(object);
        }
      }
      return nextFieldValue != null;
    }

    public Map.Entry next() {
      if (!hasNext()) {
        throw new NoSuchElementException();
      }
      currentFieldInfo = nextFieldInfo;
      Object currentFieldValue = nextFieldValue;
      isComputed = false;
      isRemoved = false;
      nextFieldInfo = null;
      nextFieldValue = null;
      return new Entry(currentFieldInfo, currentFieldValue);
    }

    public void remove() {
      Preconditions.checkState(currentFieldInfo != null && !isRemoved);
      isRemoved = true;
      currentFieldInfo.setValue(object, null);
    }
  }

  /**
   * Entry in the reflection map.
   *
   * 

Null key or value is not allowed. */ final class Entry implements Map.Entry { /** * Current field value, possibly modified only by {@link #setValue(Object)}. As specified {@link * java.util.Map.Entry}, behavior is undefined if the field value is modified by other means. */ private Object fieldValue; /** Field info. */ private final FieldInfo fieldInfo; Entry(FieldInfo fieldInfo, Object fieldValue) { this.fieldInfo = fieldInfo; this.fieldValue = Preconditions.checkNotNull(fieldValue); } public String getKey() { String result = fieldInfo.getName(); if (classInfo.getIgnoreCase()) { result = result.toLowerCase(Locale.US); } return result; } public Object getValue() { return fieldValue; } public Object setValue(Object value) { Object oldValue = fieldValue; fieldValue = Preconditions.checkNotNull(value); fieldInfo.setValue(object, value); return oldValue; } @Override public int hashCode() { return getKey().hashCode() ^ getValue().hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Map.Entry)) { return false; } Map.Entry other = (Map.Entry) obj; return getKey().equals(other.getKey()) && getValue().equals(other.getValue()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy