Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.jackson.databind.introspect;
  
  import java.util.*;
  
Helper class used for aggregating information about all possible properties of a POJO.
 
 public class POJOPropertiesCollector
 {
     /*
     /**********************************************************
     /* Configuration
     /**********************************************************
      */
    
    
Configuration settings
 
     protected final MapperConfig<?> _config;

    
True if introspection is done for serialization (giving precedence for serialization annotations), or not (false, deserialization)
 
     protected final boolean _forSerialization;
    
    
Type of POJO for which properties are being collected.
 
     protected final JavaType _type;

    
Low-level introspected class information (methods, fields etc)
 
     protected final AnnotatedClass _classDef;
 
     protected final VisibilityChecker<?> _visibilityChecker;
 
     protected final AnnotationIntrospector _annotationIntrospector;

    
Prefix used by auto-detected mutators ("setters"): usually "set", but differs for builder objects ("with" by default).
 
     protected final String _mutatorPrefix;
     
     /*
     /**********************************************************
     /* Collected property information
     /**********************************************************
      */

    
Set of logical property information collected so far
 
     protected final LinkedHashMap<StringPOJOPropertyBuilder_properties
         = new LinkedHashMap<StringPOJOPropertyBuilder>();
 
     protected LinkedList<POJOPropertyBuilder_creatorProperties = null;
     
     protected LinkedList<AnnotatedMember_anyGetters = null;
 
     protected LinkedList<AnnotatedMethod_anySetters = null;

    
Method(s) marked with 'JsonValue' annotation
 
     protected LinkedList<AnnotatedMethod_jsonValueGetters = null;

    
Lazily collected list of properties that can be implicitly ignored during serialization; only updated when collecting information for deserialization purposes
 
     protected HashSet<String_ignoredPropertyNames;

    
Lazily collected list of members that were annotated to indicate that they represent mutators for deserializer value injection.
 
     
     /*
     /**********************************************************
     /* Life-cycle
     /**********************************************************
      */
     
     protected POJOPropertiesCollector(MapperConfig<?> configboolean forSerialization,
             JavaType typeAnnotatedClass classDefString mutatorPrefix)
     {
         = config;
         = forSerialization;
         = type;
         = classDef;
         = (mutatorPrefix == null) ? "set" : mutatorPrefix;
                .getAnnotationIntrospector() : null;
        if ( == null) {
        } else {
                    .getDefaultVisibilityChecker());
        }
    }
    
    /*
    /**********************************************************
    /* Public API
    /**********************************************************
     */
    public MapperConfig<?> getConfig() {
        return ;
    }
    public JavaType getType() {
        return ;
    }
    
    public AnnotatedClass getClassDef() {
        return ;
    }
        return ;
    }
    
        // make sure we return a copy, so caller can remove entries if need be:
        return new ArrayList<BeanPropertyDefinition>(.values());
    }
    public Map<ObjectAnnotatedMembergetInjectables() {
        return ;
    }
    
    {
        // If @JsonValue defined, must have a single one
        if ( != null) {
            if (.size() > 1) {
                reportProblem("Multiple value properties defined ("+.get(0)+" vs "
                        +.get(1)+")");
            }
            // otherwise we won't greatly care
            return .get(0);
        }
        return null;
    }
    public AnnotatedMember getAnyGetter()
    {
        if ( != null) {
            if (.size() > 1) {
                reportProblem("Multiple 'any-getters' defined ("+.get(0)+" vs "
                        +.get(1)+")");
            }
            return .getFirst();
        }        
        return null;
    }
    {
        if ( != null) {
            if (.size() > 1) {
                reportProblem("Multiple 'any-setters' defined ("+.get(0)+" vs "
                        +.get(1)+")");
            }
            return .getFirst();
        }
        return null;
    }
    public Set<StringgetIgnoredPropertyNames() {
        return ;
    }

    
Accessor to find out whether type specified requires inclusion of Object Identifier.
    public ObjectIdInfo getObjectIdInfo() {
        if ( == null) {
            return null;
        }
        if (info != null) { // 2.1: may also have different defaults for refs:
            info = .findObjectReferenceInfo(info);
        }
        return info;
    }

    
Method for finding Class to use as POJO builder, if any.
    public Class<?> findPOJOBuilderClass()
    {
    }
    
    // for unit tests:
    protected Map<StringPOJOPropertyBuildergetPropertyMap() {
        return ;
    }
    /*
    /**********************************************************
    /* Public API: main-level collection
    /**********************************************************
     */

    
Method that orchestrates collection activities, and needs to be called after creating the instance.
    {
        .clear();
        
        // First: gather basic data
        _addFields();
        _addMethods();
        _addCreators();
        _addInjectables();
        // Remove ignored properties, individual entries
        _removeUnwantedProperties();
        // Rename remaining properties
        _renameProperties();
        // And use custom naming strategy, if applicable...
        PropertyNamingStrategy naming = _findNamingStrategy();
        if (naming != null) {
            _renameUsing(naming);
        }
        /* Sort by visibility (explicit over implicit); drop all but first
         * of member type (getter, setter etc) if there is visibility
         * difference
         */
        for (POJOPropertyBuilder property : .values()) {
            property.trimByVisibility();
        }
        // and then "merge" annotations
        for (POJOPropertyBuilder property : .values()) {
            property.mergeAnnotations();
        }
        /* and, if required, apply wrapper name: note, MUST be done after
         * annotations are merged.
         */
            _renameWithWrappers();
        }
        
        // well, almost last: there's still ordering...
        _sortProperties();
        return this;
    }
    /*
    /**********************************************************
    /* Overridable internal methods, sorting, other stuff
    /**********************************************************
     */
    
    /* First, order by [JACKSON-90] (explicit ordering and/or alphabetic)
     * and then for [JACKSON-170] (implicitly order creator properties before others)
     */
    protected void _sortProperties()
    {
        // Then how about explicit ordering?
        boolean sort;
        Boolean alpha = (intr == null) ? null : intr.findSerializationSortAlphabetically();
        
        if (alpha == null) {
            sort = .shouldSortPropertiesAlphabetically();
        } else {
            sort = alpha.booleanValue();
        }
        String[] propertyOrder = (intr == null) ? null : intr.findSerializationPropertyOrder();
        
        // no sorting? no need to shuffle, then
        if (!sort && ( == null) && (propertyOrder == null)) {
            return;
        }
        int size = .size();
        Map<StringPOJOPropertyBuilderall;
        // Need to (re)sort alphabetically?
        if (sort) {
            all = new TreeMap<String,POJOPropertyBuilder>();
        } else {
            all = new LinkedHashMap<String,POJOPropertyBuilder>(size+size);
        }
        for (POJOPropertyBuilder prop : .values()) {
            all.put(prop.getName(), prop);
        }
        Map<String,POJOPropertyBuilderordered = new LinkedHashMap<String,POJOPropertyBuilder>(size+size);
        // Ok: primarily by explicit order
        if (propertyOrder != null) {
            for (String name : propertyOrder) {
                POJOPropertyBuilder w = all.get(name);
                if (w == null) { // also, as per [JACKSON-268], we will allow use of "implicit" names
                    for (POJOPropertyBuilder prop : .values()) {
                        if (name.equals(prop.getInternalName())) {
                            w = prop;
                            // plus re-map to external name, to avoid dups:
                            name = prop.getName();
                            break;
                        }
                    }
                }
                if (w != null) {
                    ordered.put(namew);
                }
            }
        }
        // And secondly by sorting Creator properties before other unordered properties
        if ( != null) {
            for (POJOPropertyBuilder prop : ) {
                ordered.put(prop.getName(), prop);
            }
        }
        // And finally whatever is left (trying to put again will not change ordering)
        ordered.putAll(all);
        
        .clear();
        .putAll(ordered);
    }        
    
    /*
    /**********************************************************
    /* Overridable internal methods, adding members
    /**********************************************************
     */
    
    
Method for collecting basic information on all fields found
    protected void _addFields()
    {
        final AnnotationIntrospector ai = ;
        
        for (AnnotatedField f : .fields()) {
            String implName = f.getName();
            String explName;
            if (ai == null) {
                explName = null;
            } else if () {
                /* 18-Aug-2011, tatu: As per existing unit tests, we should only
                 *   use serialization annotation (@JsonSerializer) when serializing
                 *   fields, and similarly for deserialize-only annotations... so
                 *   no fallbacks in this particular case.
                 */
                PropertyName pn = ai.findNameForSerialization(f);
                explName = (pn == null) ? null : pn.getSimpleName();
            } else {
                PropertyName pn = ai.findNameForDeserialization(f);
                explName = (pn == null) ? null : pn.getSimpleName();
            }
            if ("".equals(explName)) { // empty String meaning "use default name", here just means "same as field name"
                explName = implName;
            }
            // having explicit name means that field is visible; otherwise need to check the rules
            boolean visible = (explName != null);
            if (!visible) {
                visible = .isFieldVisible(f);
            }
            // and finally, may also have explicit ignoral
            boolean ignored = (ai != null) && ai.hasIgnoreMarker(f);
            _property(implName).addField(fexplNamevisibleignored);
        }
    }

    
Method for collecting basic information on constructor(s) found
    protected void _addCreators()
    {
        final AnnotationIntrospector ai = ;
        // can be null if annotation processing is disabled...
        if (ai == null) {
            return;
        }
        for (AnnotatedConstructor ctor : .getConstructors()) {
            if ( == null) {
                 = new LinkedList<POJOPropertyBuilder>();
            }
            for (int i = 0, len = ctor.getParameterCount(); i < len; ++i) {
                AnnotatedParameter param = ctor.getParameter(i);
                PropertyName pn = ai.findNameForDeserialization(param);
                String name = (pn == null) ? null : pn.getSimpleName();
                // is it legal not to have name?
                if (name != null) {
                    // shouldn't need to worry about @JsonIgnore (no real point, so)
                    POJOPropertyBuilder prop = _property(name);
                    prop.addCtor(paramnametruefalse);
                    .add(prop);
                }
            }
        }
        for (AnnotatedMethod factory : .getStaticMethods()) {
            if ( == null) {
                 = new LinkedList<POJOPropertyBuilder>();
            }
            for (int i = 0, len = factory.getParameterCount(); i < len; ++i) {
                AnnotatedParameter param = factory.getParameter(i);
                PropertyName pn = ai.findNameForDeserialization(param);
                String name = (pn == null) ? null : pn.getSimpleName();
                // is it legal not to have name?
                if (name != null) {
                    // shouldn't need to worry about @JsonIgnore (no real point, so)
                    POJOPropertyBuilder prop = _property(name);
                    prop.addCtor(paramnametruefalse);
                    .add(prop);
                }
            }
        }
    }

    
Method for collecting basic information on all fields found
    protected void _addMethods()
    {
        final AnnotationIntrospector ai = ;
        
        for (AnnotatedMethod m : .memberMethods()) {
            /* For methods, handling differs between getters and setters; and
             * we will also only consider entries that either follow the bean
             * naming convention or are explicitly marked: just being visible
             * is not enough (unlike with fields)
             */
            int argCount = m.getParameterCount();
            if (argCount == 0) { // getters (including 'any getter')
            	_addGetterMethod(mai);
            } else if (argCount == 1) { // setters
            	_addSetterMethod(mai);
            } else if (argCount == 2) { // any getter?
                if (ai != null  && ai.hasAnySetterAnnotation(m)) {
                    if ( == null) {
                         = new LinkedList<AnnotatedMethod>();
                    }
                    .add(m);
                }
            }
        }
    }
    {
        // any getter?
        if (ai != null) {
            if (ai.hasAnyGetterAnnotation(m)) {
                if ( == null) {
                     = new LinkedList<AnnotatedMember>();
                }
                .add(m);
                return;
            }
            // @JsonValue?
            if (ai.hasAsValueAnnotation(m)) {
                if ( == null) {
                     = new LinkedList<AnnotatedMethod>();
                }
                .add(m);
                return;
            }
        }
        String implName// from naming convention
        boolean visible;
        
        PropertyName pn = (ai == null) ? null : ai.findNameForSerialization(m);
        String explName = (pn == null) ? null : pn.getSimpleName();
        if (explName == null) { // no explicit name; must follow naming convention
            implName = BeanUtil.okNameForRegularGetter(mm.getName());
            if (implName == null) { // if not, must skip
                implName = BeanUtil.okNameForIsGetter(mm.getName());
                if (implName == null) {
                    return;
                }
                visible = .isIsGetterVisible(m);
            } else {
                visible = .isGetterVisible(m);
            }
        } else { // explicit indication of inclusion, but may be empty
            // we still need implicit name to link with other pieces
            implName = BeanUtil.okNameForGetter(m);
            // if not regular getter name, use method name as is
            if (implName == null) {
                implName = m.getName();
            }
            if (explName.length() == 0) {
                explName = implName;
            }
            visible = true;
        }
        boolean ignore = (ai == null) ? false : ai.hasIgnoreMarker(m);
        _property(implName).addGetter(mexplNamevisibleignore);
    }
    {
        String implName// from naming convention
        boolean visible;
        PropertyName pn = (ai == null) ? null : ai.findNameForDeserialization(m);
        String explName = (pn == null) ? null : pn.getSimpleName();
        if (explName == null) { // no explicit name; must follow naming convention
            implName = BeanUtil.okNameForMutator(m);
            if (implName == null) { // if not, must skip
            	return;
            }
            visible = .isSetterVisible(m);
        } else { // explicit indication of inclusion, but may be empty
            // we still need implicit name to link with other pieces
            implName = BeanUtil.okNameForMutator(m);
            // if not regular getter name, use method name as is
            if (implName == null) {
                implName = m.getName();
            }
            if (explName.length() == 0) { 
                explName = implName;
            }
            visible = true;
        }
        boolean ignore = (ai == null) ? false : ai.hasIgnoreMarker(m);
        _property(implName).addSetter(mexplNamevisibleignore);
    }
    
    protected void _addInjectables()
    {
        final AnnotationIntrospector ai = ;
        if (ai == null) {
            return;
        }
        
        // first fields, then methods
        for (AnnotatedField f : .fields()) {
            _doAddInjectable(ai.findInjectableValueId(f), f);
        }
        
        for (AnnotatedMethod m : .memberMethods()) {
            /* for now, only allow injection of a single arg
             * (to be changed in future)
             */
            if (m.getParameterCount() != 1) {
                continue;
            }
            _doAddInjectable(ai.findInjectableValueId(m), m);
        }
    }
    protected void _doAddInjectable(Object idAnnotatedMember m)
    {
        if (id == null) {
            return;
        }
        if ( == null) {
             = new LinkedHashMap<ObjectAnnotatedMember>();
        }
        AnnotatedMember prev = .put(idm);
        if (prev != null) {
            String type = (id == null) ? "[null]" : id.getClass().getName();
            throw new IllegalArgumentException("Duplicate injectable value with id '"
                    +String.valueOf(id)+"' (of type "+type+")");
        }
    }
    
    /*
    /**********************************************************
    /* Internal methods; removing ignored properties
    /**********************************************************
     */

    
Method called to get rid of candidate properties that are marked as ignored, or that are not visible.
    protected void _removeUnwantedProperties()
    {
        while (it.hasNext()) {
            Map.Entry<StringPOJOPropertyBuilderentry = it.next();
            POJOPropertyBuilder prop = entry.getValue();
            // First: if nothing visible, just remove altogether
            if (!prop.anyVisible()) {
                it.remove();
                continue;
            }
            // Otherwise, check ignorals
            if (prop.anyIgnorals()) {
                // first: if one or more ignorals, and no explicit markers, remove the whole thing
                if (!prop.isExplicitlyIncluded()) {
                    it.remove();
                    _addIgnored(prop.getName());
                    continue;
                }
                // otherwise just remove ones marked to be ignored
                prop.removeIgnored();
                if (! && !prop.couldDeserialize()) {
                    _addIgnored(prop.getName());
                }
            }
            // and finally, handle removal of individual non-visible elements
            prop.removeNonVisible();
        }
    }
    
    private void _addIgnored(String name)
    {
        if (!) {
            if ( == null) {
                 = new HashSet<String>();
            }
            .add(name);
        }
    }
    /*
    /**********************************************************
    /* Internal methods; renaming properties
    /**********************************************************
     */
    protected void _renameProperties()
    {
        // With renaming need to do in phases: first, find properties to rename
        LinkedList<POJOPropertyBuilderrenamed = null;
        while (it.hasNext()) {
            Map.Entry<StringPOJOPropertyBuilderentry = it.next();
            POJOPropertyBuilder prop = entry.getValue();
            String newName = prop.findNewName();
            if (newName != null) {
                if (renamed == null) {
                    renamed = new LinkedList<POJOPropertyBuilder>();
                }
                prop = prop.withName(newName);
                renamed.add(prop);
                it.remove();
            }
        }
        
        // and if any were renamed, merge back in...
        if (renamed != null) {
            for (POJOPropertyBuilder prop : renamed) {
                String name = prop.getName();
                POJOPropertyBuilder old = .get(name);
                if (old == null) {
                    .put(nameprop);
                } else {
                    old.addAll(prop);
                }
            }
        }
    }
    protected void _renameUsing(PropertyNamingStrategy naming)
    {
        .clear();
        for (POJOPropertyBuilder prop : props) {
            String name = prop.getName();
            if () {
                if (prop.hasGetter()) {
                    name = naming.nameForGetterMethod(prop.getGetter(), name);
                } else if (prop.hasField()) {
                    name = naming.nameForField(prop.getField(), name);
                }
            } else {
                if (prop.hasSetter()) {
                    name = naming.nameForSetterMethod(prop.getSetter(), name);
                } else if (prop.hasConstructorParameter()) {
                    name = naming.nameForConstructorParameter(prop.getConstructorParameter(), name);
                } else if (prop.hasField()) {
                    name = naming.nameForField(prop.getField(), name);
                } else if (prop.hasGetter()) {
                    /* Plus, when getter-as-setter is used, need to convert that too..
                     * (should we verify that's enabled? For now, assume it's ok always)
                     */
                    name = naming.nameForGetterMethod(prop.getGetter(), name);
                }
            }
            if (!name.equals(prop.getName())) {
                prop = prop.withName(name);
            }
            /* As per [JACKSON-687], need to consider case where there may already be
             * something in there...
             */
            POJOPropertyBuilder old = .get(name);
            if (old == null) {
                .put(nameprop);
            } else {
                old.addAll(prop);
            }
        }
    }
    protected void _renameWithWrappers()
    {
        /* 11-Sep-2012, tatu: To support 'MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME',
         *   need another round of renaming...
         */
        LinkedList<POJOPropertyBuilderrenamed = null;
        while (it.hasNext()) {
            Map.Entry<StringPOJOPropertyBuilderentry = it.next();
            POJOPropertyBuilder prop = entry.getValue();
            AnnotatedMember member = prop.getPrimaryMember();
            if (member == null) {
                continue;
            }
            PropertyName wrapperName = .findWrapperName(member);
            if (wrapperName == null || !wrapperName.hasSimpleName()) {
                continue;
            }
            String name = wrapperName.getSimpleName();
            if (!name.equals(prop.getName())) {
                if (renamed == null) {
                    renamed = new LinkedList<POJOPropertyBuilder>();
                }
                prop = prop.withName(name);
                renamed.add(prop);
                it.remove();
            }
        }
        // and if any were renamed, merge back in...
        if (renamed != null) {
            for (POJOPropertyBuilder prop : renamed) {
                String name = prop.getName();
                POJOPropertyBuilder old = .get(name);
                if (old == null) {
                    .put(nameprop);
                } else {
                    old.addAll(prop);
                }
            }
        }
    }
    
    
    /*
    /**********************************************************
    /* Internal methods; helpers
    /**********************************************************
     */
    protected void reportProblem(String msg) {
        throw new IllegalArgumentException("Problem with definition of "++": "+msg);
    }
    
    protected POJOPropertyBuilder _property(String implName)
    {
        POJOPropertyBuilder prop = .get(implName);
        if (prop == null) {
            prop = new POJOPropertyBuilder(implName,
                    );
            .put(implNameprop);
        }
        return prop;
    }
    {
        Object namingDef = ( == null)? null
                : .findNamingStrategy();
        if (namingDef == null) {
            return .getPropertyNamingStrategy();
        }
        if (namingDef instanceof PropertyNamingStrategy) {
            return (PropertyNamingStrategynamingDef;
        }
        /* Alas, there's no way to force return type of "either class
         * X or Y" -- need to throw an exception after the fact
         */
        if (!(namingDef instanceof Class)) {
            throw new IllegalStateException("AnnotationIntrospector returned PropertyNamingStrategy definition of type "
                    +namingDef.getClass().getName()+"; expected type PropertyNamingStrategy or Class<PropertyNamingStrategy> instead");
        }
        Class<?> namingClass = (Class<?>)namingDef;
        if (!PropertyNamingStrategy.class.isAssignableFrom(namingClass)) {
            throw new IllegalStateException("AnnotationIntrospector returned Class "
                    +namingClass.getName()+"; expected Class<PropertyNamingStrategy>");
        }
        if (hi != null) {
            return hi.namingStrategyInstance(namingClass);
        }
        return (PropertyNamingStrategy) ClassUtil.createInstance(namingClass,
                    .canOverrideAccessModifiers());
    }
New to GrepCode? Check out our FAQ X