Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.jackson.databind.deser.impl;
  
  import java.util.*;
  
Helper class used for storing mapping from property name to com.fasterxml.jackson.databind.deser.SettableBeanProperty instances.

Note that this class is used instead of generic java.util.HashMap for bit of performance gain (and some memory savings): although default implementation is very good for generic use cases, it can be streamlined a bit for specific use case we have. Even relatively small improvements matter since this is directly on the critical path during deserialization, as it is done for each and every POJO property deserialized.

 
 public final class BeanPropertyMap
     implements Iterable<SettableBeanProperty>,
         java.io.Serializable // since 2.1
 {
     private static final long serialVersionUID = 1L;
 
     private final Bucket[] _buckets;
     
     private final int _hashMask;
 
     private final int _size;

    
Counter we use to keep track of insertion order of properties (to be able to recreate insertion order when needed).

Note: is kept up-to-date with additions, but can NOT handle removals (i.e. "holes" may be left)

 
     private int _nextBucketIndex = 0;
 
     public BeanPropertyMap(Collection<SettableBeanPropertyproperties)
     {
          = properties.size();
         int bucketCount = findSize();
          = bucketCount-1;
         Bucket[] buckets = new Bucket[bucketCount];
         for (SettableBeanProperty property : properties) {
             String key = property.getName();
             int index = key.hashCode() & ;
             buckets[index] = new Bucket(buckets[index], keyproperty++);
         }
          = buckets;
     }
 
     private BeanPropertyMap(Bucket[] bucketsint sizeint index)
     {
          = buckets;
          = size;
          = buckets.length-1;
          = index;
     }
    
    
Fluent copy method that creates a new instance that is a copy of this instance except for one additional property that is passed as the argument. Note that method does not modify this instance but constructs and returns a new one.

Since:
2.0
 
     public BeanPropertyMap withProperty(SettableBeanProperty newProperty)
     {
     	// first things first: can just copy hash area:
     	final int bcount = .;
         Bucket[] newBuckets = new Bucket[bcount];
         System.arraycopy(, 0, newBuckets, 0, bcount);
         final String propName = newProperty.getName();
         // and then see if it's add or replace:
     	SettableBeanProperty oldProp = find(newProperty.getName());
     	if (oldProp == null) { // add
     	    // first things first: add or replace?
     	    // can do a straight copy, since all additions are at the front
     	    // and then insert the new property:
     	    int index = propName.hashCode() & ;
     	    newBuckets[index] = new Bucket(newBuckets[index],
     	            propNamenewProperty++);
     	    return new BeanPropertyMap(newBuckets+1, );
     	}
     	// replace: easy, close + replace
     	BeanPropertyMap newMap = new BeanPropertyMap(newBucketsbcount);
     	newMap.replace(newProperty);
     	return newMap;
     }
    
    
Factory method for constructing a map where all entries use given prefix
 
    public BeanPropertyMap renameAll(NameTransformer transformer)
    {
        if (transformer == null || (transformer == .)) {
            return this;
        }
        Iterator<SettableBeanPropertyit = iterator();
        ArrayList<SettableBeanPropertynewProps = new ArrayList<SettableBeanProperty>();
        while (it.hasNext()) {
            SettableBeanProperty prop = it.next();
            String newName = transformer.transform(prop.getName());
            prop = prop.withName(newName);
            JsonDeserializer<?> deser = prop.getValueDeserializer();
            if (deser != null) {
                @SuppressWarnings("unchecked")
                JsonDeserializer<ObjectnewDeser = (JsonDeserializer<Object>)
                    deser.unwrappingDeserializer(transformer);
                if (newDeser != deser) {
                    prop = prop.withValueDeserializer(newDeser);
                }
            }
            newProps.add(prop);
        }
        // should we try to re-index? Ordering probably changed but called probably doesn't want changes...
        return new BeanPropertyMap(newProps);
    }
    
    {
        // order is arbitrary, but stable:
        int index = 0;
        for (Bucket bucket : ) {
            while (bucket != null) {
                bucket.value.assignIndex(index++);
                bucket = bucket.next;
            }
        }
        return this;
    }
    
    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;
    }
    /*
    /**********************************************************
    /* Iterable, for convenient iterating over all properties
    /**********************************************************
     */
    
    
Accessor for traversing over all contained properties.
//    @Override
        return new IteratorImpl();
    }
    
    
Method that will re-create initial insertion-ordering of properties contained in this map. Note that if properties have been removed, array may contain nulls; otherwise it should be consecutive.

Since:
2.1
    {
        int len = ;
        SettableBeanProperty[] result = new SettableBeanProperty[len];
        for (Bucket root : ) {
            for (Bucket bucket = rootbucket != nullbucket = bucket.next) {
                result[bucket.index] = bucket.value;
            }
        }
        return result;
    }
    /*
    /**********************************************************
    /* Public API
    /**********************************************************
     */
    public int size() { return ; }
    
    public SettableBeanProperty find(String key)
    {
        int index = key.hashCode() & ;
        Bucket bucket = [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(keyindex);
    }

    
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() & (.-1);
        /* This is bit tricky just because buckets themselves
         * are immutable, so we need to recreate the chain. Fine.
         */
        Bucket tail = null;
        int foundIndex = -1;
        
        for (Bucket bucket = [index]; bucket != nullbucket = bucket.next) {
            // match to remove?
            if (foundIndex < 0 && bucket.key.equals(name)) {
                foundIndex = bucket.index;
            } else {
                tail = new Bucket(tailbucket.keybucket.valuebucket.index);
            }
        }
        // Not finding specified entry is error, so:
        if (foundIndex < 0) {
            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
         */
        [index] = new Bucket(tailnamepropertyfoundIndex);
    }

    
Specialized method for removing specified existing entry. NOTE: entry MUST exist, otherwise an exception is thrown.
    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() & (.-1);
        Bucket tail = null;
        boolean found = false;
        // slightly complex just because chain is immutable, must recreate
        for (Bucket bucket = [index]; bucket != nullbucket = bucket.next) {
            // match to remove?
            if (!found && bucket.key.equals(name)) {
                found = true;
            } else {
                tail = new Bucket(tailbucket.keybucket.valuebucket.index);
            }
        }
        if (!found) { // must be found
            throw new NoSuchElementException("No entry '"+property+"' found, can't remove");
        }
        [index] = tail;
    }
    
    /*
    /**********************************************************
    /* Helper methods
    /**********************************************************
     */
    
    private SettableBeanProperty _findWithEquals(String keyint index)
    {
        Bucket bucket = [index];
        while (bucket != null) {
            if (key.equals(bucket.key)) {
                return bucket.value;
            }
            bucket = bucket.next;
        }
        return null;
    }
    /*
    /**********************************************************
    /* Helper beans
    /**********************************************************
     */
    
    private final static class Bucket
        implements java.io.Serializable
    {
        private static final long serialVersionUID = 1L;
        public final Bucket next;
        public final String key;
        public final SettableBeanProperty value;

        
Index that indicates insertion order of the bucket
        public final int index;
        
        public Bucket(Bucket nextString keySettableBeanProperty valueint index)
        {
            this. = next;
            this. = key;
            this. = value;
            this. = index;
        }
    }
    private final static class IteratorImpl
        implements Iterator<SettableBeanProperty>
    {
        
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;
            // need to initialize to point to first entry...
            int i = 0;
            for (int len = .i < len; ) {
                Bucket b = [i++];
                if (b != null) {
                     = b;
                    break;
                }
            }
             = i;
        }
//        @Override
        public boolean hasNext() {
            return  != null;
        }
//        @Override
        public SettableBeanProperty next()
        {
            Bucket curr = ;
            if (curr == null) { // sanity check
                throw new NoSuchElementException();
            }
            // need to advance, too
            Bucket b = curr.next;
            while (b == null &&  < .) {
                b = [++];
            }
             = b;
            return curr.value;
        }
//       @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
New to GrepCode? Check out our FAQ X