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

org.codehaus.jackson.map.deser.impl.BeanPropertyMap Maven / Gradle / Ivy

Go to download

Data Mapper package is a high-performance data binding package built on Jackson JSON processor

The newest version!
package org.codehaus.jackson.map.deser.impl;

import java.util.*;

import org.codehaus.jackson.map.deser.SettableBeanProperty;

/**
 * Helper class used for storing mapping from property name to
 * {@link SettableBeanProperty} instances.
 *

* Note that this class is used instead of generic {@link java.util.HashMap} * is performance: although default implementation is very good for generic * use cases, it can still be streamlined a bit for specific use case * we have. * * @since 1.7 */ public final class BeanPropertyMap { private final Bucket[] _buckets; private final int _hashMask; private final int _size; public BeanPropertyMap(Collection properties) { _size = properties.size(); int bucketCount = findSize(_size); _hashMask = bucketCount-1; Bucket[] buckets = new Bucket[bucketCount]; for (SettableBeanProperty property : properties) { String key = property.getName(); int index = key.hashCode() & _hashMask; buckets[index] = new Bucket(buckets[index], key, property); } _buckets = buckets; } public void assignIndexes() { // order is arbitrary, but stable: int index = 0; for (Bucket bucket : _buckets) { while (bucket != null) { bucket.value.assignIndex(index++); bucket = bucket.next; } } } private final static int findSize(int size) { // For small enough results (32 or less), we'll require <= 50% fill rate; otherwise 80% int needed = (size <= 32) ? (size + size) : (size + (size >> 2)); int result = 2; while (result < needed) { result += result; } return result; } /* /********************************************************** /* Public API /********************************************************** */ public int size() { return _size; } /** * Accessor for traversing over all contained properties. */ public Iterator allProperties() { return new IteratorImpl(_buckets); } public SettableBeanProperty find(String key) { int index = key.hashCode() & _hashMask; Bucket bucket = _buckets[index]; // Let's unroll first lookup since that is null or match in 90+% cases if (bucket == null) { return null; } // Primarily we do just identity comparison as keys should be interned if (bucket.key == key) { return bucket.value; } while ((bucket = bucket.next) != null) { if (bucket.key == key) { return bucket.value; } } // Do we need fallback for non-interned Strings? return _findWithEquals(key, index); } /** * Specialized method that can be used to replace an existing entry * (note: entry MUST exist; otherwise exception is thrown) with * specified replacement. */ public void replace(SettableBeanProperty property) { String name = property.getName(); int index = name.hashCode() & (_buckets.length-1); /* This is bit tricky just because buckets themselves * are immutable, so we need to recreate the chain. Fine. */ Bucket tail = null; boolean found = false; for (Bucket bucket = _buckets[index]; bucket != null; bucket = bucket.next) { // match to remove? if (!found && bucket.key.equals(name)) { found = true; } else { tail = new Bucket(tail, bucket.key, bucket.value); } } // Not finding specified entry is error, so: if (!found) { throw new NoSuchElementException("No entry '"+property+"' found, can't replace"); } /* So let's attach replacement in front: useful also because * it allows replacement even when iterating over entries */ _buckets[index] = new Bucket(tail, name, property); } /** * Specialized method for removing specified existing entry. * NOTE: entry MUST exist, otherwise an exception is thrown. * * @since 1.9 */ public void remove(SettableBeanProperty property) { // Mostly this is the same as code with 'replace', just bit simpler... String name = property.getName(); int index = name.hashCode() & (_buckets.length-1); Bucket tail = null; boolean found = false; // slightly complex just because chain is immutable, must recreate for (Bucket bucket = _buckets[index]; bucket != null; bucket = bucket.next) { // match to remove? if (!found && bucket.key.equals(name)) { found = true; } else { tail = new Bucket(tail, bucket.key, bucket.value); } } if (!found) { // must be found throw new NoSuchElementException("No entry '"+property+"' found, can't remove"); } _buckets[index] = tail; } /* /********************************************************** /* Helper methods /********************************************************** */ private SettableBeanProperty _findWithEquals(String key, int index) { Bucket bucket = _buckets[index]; while (bucket != null) { if (key.equals(bucket.key)) { return bucket.value; } bucket = bucket.next; } return null; } /* /********************************************************** /* Helper beans /********************************************************** */ private final static class Bucket { public final Bucket next; public final String key; public final SettableBeanProperty value; public Bucket(Bucket next, String key, SettableBeanProperty value) { this.next = next; this.key = key; this.value = value; } } private final static class IteratorImpl implements Iterator { /** * Buckets of the map */ private final Bucket[] _buckets; /** * Bucket that contains next value to return (if any); null if nothing more to iterate */ private Bucket _currentBucket; /** * Index of the next bucket in bucket array to check. */ private int _nextBucketIndex; public IteratorImpl(Bucket[] buckets) { _buckets = buckets; // need to initialize to point to first entry... int i = 0; for (int len = _buckets.length; i < len; ) { Bucket b = _buckets[i++]; if (b != null) { _currentBucket = b; break; } } _nextBucketIndex = i; } @Override public boolean hasNext() { return _currentBucket != null; } @Override public SettableBeanProperty next() { Bucket curr = _currentBucket; if (curr == null) { // sanity check throw new NoSuchElementException(); } // need to advance, too Bucket b = curr.next; while (b == null && _nextBucketIndex < _buckets.length) { b = _buckets[_nextBucketIndex++]; } _currentBucket = b; return curr.value; } @Override public void remove() { throw new UnsupportedOperationException(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy