Jackson Data Binding Source Code

Jackson is "the Java JSON library" or "the best JSON parser for Java". Or simply as "JSON for Java".

  • Jackson Data Binding module allows you to converts JSON to and from POJO (Plain Old Java Object) using property accessor or using annotations.
  • Jackson Databind Source Code files are provided in the source packge (jackson-databind-2.12.4-sources.jar). You can download it at Jackson Maven Website.

    You can also browse Jackson Databind Source Code below:

    ✍: FYIcenter.com

    com/fasterxml/jackson/databind/introspect/AnnotatedCreatorCollector.java

    package com.fasterxml.jackson.databind.introspect;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.AnnotatedElement;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    import com.fasterxml.jackson.databind.AnnotationIntrospector;
    import com.fasterxml.jackson.databind.JavaType;
    import com.fasterxml.jackson.databind.introspect.AnnotatedClass.Creators;
    import com.fasterxml.jackson.databind.type.TypeFactory;
    import com.fasterxml.jackson.databind.util.ClassUtil;
    
    /**
     * Helper class used to contain details of how Creators (annotated constructors
     * and static methods) are discovered to be accessed by and via {@link AnnotatedClass}.
     *
     * @since 2.9
     */
    final class AnnotatedCreatorCollector
        extends CollectorBase
    {
        // // // Configuration
    
        private final TypeResolutionContext _typeContext;
    
        /**
         * @since 2.11
         */
        private final boolean _collectAnnotations;
    
        // // // Collected state
    
        private AnnotatedConstructor _defaultConstructor;
    
        AnnotatedCreatorCollector(AnnotationIntrospector intr,
                TypeResolutionContext tc, boolean collectAnnotations)
        {
            super(intr);
            _typeContext = tc;
            _collectAnnotations = collectAnnotations;
        }
    
        /**
         * @since 2.11.3
         */
        public static Creators collectCreators(AnnotationIntrospector intr,
                TypeFactory typeFactory, TypeResolutionContext tc,
                JavaType type, Class<?> primaryMixIn, boolean collectAnnotations)
        {
            // 30-Sep-2020, tatu: [databind#2795] Even if annotations not otherwise
            //  requested (for JDK collections), force change if mix-in in use
            collectAnnotations |= (primaryMixIn != null);
    
            // Constructor also always members of resolved class, parent == resolution context
            return new AnnotatedCreatorCollector(intr, tc, collectAnnotations)
                    .collect(typeFactory, type, primaryMixIn);
        }
    
        Creators collect(TypeFactory typeFactory, JavaType type, Class<?> primaryMixIn)
        {
        // 30-Apr-2016, tatu: [databind#1215]: Actually, while true, this does
        //   NOT apply to context since sub-class may have type bindings
    //        TypeResolutionContext typeContext = new TypeResolutionContext.Basic(_typeFactory, _type.getBindings());
    
            List<AnnotatedConstructor> constructors = _findPotentialConstructors(type, primaryMixIn);
            List<AnnotatedMethod> factories = _findPotentialFactories(typeFactory, type, primaryMixIn);
    
            /* And then... let's remove all constructors that are deemed
             * ignorable after all annotations have been properly collapsed.
             */
            // AnnotationIntrospector is null if annotations not enabled; if so, can skip:
            if (_collectAnnotations) {
                if (_defaultConstructor != null) {
                    if (_intr.hasIgnoreMarker(_defaultConstructor)) {
                        _defaultConstructor = null;
                    }
                }
                // count down to allow safe removal
                for (int i = constructors.size(); --i >= 0; ) {
                    if (_intr.hasIgnoreMarker(constructors.get(i))) {
                        constructors.remove(i);
                    }
                }
                for (int i = factories.size(); --i >= 0; ) {
                    if (_intr.hasIgnoreMarker(factories.get(i))) {
                        factories.remove(i);
                    }
                }
            }
            return new AnnotatedClass.Creators(_defaultConstructor, constructors, factories);
        }
    
        /**
         * Helper method for locating constructors (and matching mix-in overrides)
         * we might want to use; this is needed in order to mix information between
         * the two and construct resulting {@link AnnotatedConstructor}s
         */
        private List<AnnotatedConstructor> _findPotentialConstructors(JavaType type,
                Class<?> primaryMixIn)
        {
            ClassUtil.Ctor defaultCtor = null;
            List<ClassUtil.Ctor> ctors = null;
    
            // 18-Jun-2016, tatu: Enum constructors will never be useful (unlike
            //    possibly static factory methods); but they can be royal PITA
            //    due to some oddities by JVM; see:
            //    [https://github.com/FasterXML/jackson-module-parameter-names/issues/35]
            //    for more. So, let's just skip them.
            if (!type.isEnumType()) {
                ClassUtil.Ctor[] declaredCtors = ClassUtil.getConstructors(type.getRawClass());
                for (ClassUtil.Ctor ctor : declaredCtors) {
                    if (!isIncludableConstructor(ctor.getConstructor())) {
                        continue;
                    }
                    if (ctor.getParamCount() == 0) {
                        defaultCtor = ctor;
                    } else {
                        if (ctors == null) {
                            ctors = new ArrayList<>();
                        }
                        ctors.add(ctor);
                    }
                }
            }
            List<AnnotatedConstructor> result;
            int ctorCount;
            if (ctors == null) {
                result = Collections.emptyList();
                // Nothing found? Short-circuit
                if (defaultCtor == null) { 
                    return result;
                }
                ctorCount = 0;
            } else {
                ctorCount = ctors.size();
                result = new ArrayList<>(ctorCount);
                for (int i = 0; i < ctorCount; ++i) {
                    result.add(null);
                }
            }
    
            // so far so good; but do we also need to find mix-ins overrides?
            if (primaryMixIn != null) {
                MemberKey[] ctorKeys = null;
                for (ClassUtil.Ctor mixinCtor : ClassUtil.getConstructors(primaryMixIn)) {
                    if (mixinCtor.getParamCount() == 0) {
                        if (defaultCtor != null) {
                            _defaultConstructor = constructDefaultConstructor(defaultCtor, mixinCtor);
                            defaultCtor = null;
                        }
                        continue;
                    }
                    if (ctors != null) {
                        if (ctorKeys == null) {
                            ctorKeys = new MemberKey[ctorCount];
                            for (int i = 0; i < ctorCount; ++i) {
                                ctorKeys[i] = new MemberKey(ctors.get(i).getConstructor());
                            }
                        }
                        MemberKey key = new MemberKey(mixinCtor.getConstructor());
        
                        for (int i = 0; i < ctorCount; ++i) {
                            if (key.equals(ctorKeys[i])) {
                                result.set(i,
                                        constructNonDefaultConstructor(ctors.get(i), mixinCtor));
                                break;
                            }
                        }
                    }
                }
            }
            // Ok: anything within mix-ins has been resolved; anything remaining we must resolve
            if (defaultCtor != null) {
                _defaultConstructor = constructDefaultConstructor(defaultCtor, null);
            }
            for (int i = 0; i < ctorCount; ++i) {
                AnnotatedConstructor ctor = result.get(i);
                if (ctor == null) {
                    result.set(i,
                            constructNonDefaultConstructor(ctors.get(i), null));
                }
            }
            return result;
        }
    
        private List<AnnotatedMethod> _findPotentialFactories(TypeFactory typeFactory,
                JavaType type, Class<?> primaryMixIn)
        {
            List<Method> candidates = null;
    
            // First find all potentially relevant static methods
            for (Method m : ClassUtil.getClassMethods(type.getRawClass())) {
                if (!_isIncludableFactoryMethod(m)) {
                    continue;
                }
                // all factory methods are fine:
                //int argCount = m.getParameterTypes().length;
                if (candidates == null) {
                    candidates = new ArrayList<>();
                }
                candidates.add(m);
            }
            // and then locate mix-ins, if any
            if (candidates == null) {
                return Collections.emptyList();
            }
            // 05-Sep-2020, tatu: Important fix wrt [databind#2821] -- static methods
            //   do NOT have type binding context of the surrounding class and although
            //   passing that should not break things, it appears to... Regardless,
            //   it should not be needed or useful as those bindings are only available
            //   to non-static members
    //        final TypeResolutionContext typeResCtxt = new TypeResolutionContext.Empty(typeFactory);
    
            // 27-Oct-2020, tatu: SIGH. As per [databind#2894] there is widespread use of
            //   incorrect bindings in the wild -- not supported (no tests) but used
            //   nonetheless. So, for 2.11.x, put back "Bad Bindings"...
    //        final TypeResolutionContext typeResCtxt = _typeContext;
    
            // 03-Nov-2020, ckozak: Implement generic JsonCreator TypeVariable handling [databind#2895]
            final TypeResolutionContext emptyTypeResCtxt = new TypeResolutionContext.Empty(typeFactory);
    
            int factoryCount = candidates.size();
            List<AnnotatedMethod> result = new ArrayList<>(factoryCount);
            for (int i = 0; i < factoryCount; ++i) {
                result.add(null);
            }
            // so far so good; but do we also need to find mix-ins overrides?
            if (primaryMixIn != null) {
                MemberKey[] methodKeys = null;
                for (Method mixinFactory : primaryMixIn.getDeclaredMethods()) {
                    if (!_isIncludableFactoryMethod(mixinFactory)) {
                        continue;
                    }
                    if (methodKeys == null) {
                        methodKeys = new MemberKey[factoryCount];
                        for (int i = 0; i < factoryCount; ++i) {
                            methodKeys[i] = new MemberKey(candidates.get(i));
                        }
                    }
                    MemberKey key = new MemberKey(mixinFactory);
                    for (int i = 0; i < factoryCount; ++i) {
                        if (key.equals(methodKeys[i])) {
                            result.set(i,
                                    constructFactoryCreator(candidates.get(i),
                                            emptyTypeResCtxt, mixinFactory));
                            break;
                        }
                    }
                }
            }
            // Ok: anything within mix-ins has been resolved; anything remaining we must resolve
            for (int i = 0; i < factoryCount; ++i) {
                AnnotatedMethod factory = result.get(i);
                if (factory == null) {
                    Method candidate = candidates.get(i);
                    // 06-Nov-2020, tatu: Fix from [databind#2895] will try to resolve
                    //   nominal static method type bindings into expected target type
                    //   (if generic types involved)
                    TypeResolutionContext typeResCtxt = MethodGenericTypeResolver.narrowMethodTypeParameters(
                            candidate, type, typeFactory, emptyTypeResCtxt);
                    result.set(i,
                            constructFactoryCreator(candidate, typeResCtxt, null));
                }
            }
            return result;
        }
    
        private static boolean _isIncludableFactoryMethod(Method m)
        {
            return Modifier.isStatic(m.getModifiers())
                    // 09-Nov-2020, ckozak: Avoid considering synthetic methods such as
                    // lambdas used within methods because they're not relevant.
                    && !m.isSynthetic();
        }
    
        protected AnnotatedConstructor constructDefaultConstructor(ClassUtil.Ctor ctor,
                ClassUtil.Ctor mixin)
        {
            return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
                    collectAnnotations(ctor, mixin),
                    // 16-Jun-2019, tatu: default is zero-args, so can't have parameter annotations
                    NO_ANNOTATION_MAPS);
        }
    
        protected AnnotatedConstructor constructNonDefaultConstructor(ClassUtil.Ctor ctor,
                ClassUtil.Ctor mixin)
        {
            final int paramCount = ctor.getParamCount();
            if (_intr == null) { // when annotation processing is disabled
                return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
                        _emptyAnnotationMap(), _emptyAnnotationMaps(paramCount));
            }
    
            /* Looks like JDK has discrepancy, whereas annotations for implicit 'this'
             * (for non-static inner classes) are NOT included, but type is?
             * Strange, sounds like a bug. Alas, we can't really fix that...
             */
            if (paramCount == 0) { // no-arg default constructors, can simplify slightly
                return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
                        collectAnnotations(ctor, mixin),
                        NO_ANNOTATION_MAPS);
            }
            // Also: enum value constructors
            AnnotationMap[] resolvedAnnotations;
            Annotation[][] paramAnns = ctor.getParameterAnnotations();
            if (paramCount != paramAnns.length) {
                // Limits of the work-around (to avoid hiding real errors):
                // first, only applicable for member classes and then either:
    
                resolvedAnnotations = null;
                Class<?> dc = ctor.getDeclaringClass();
                // (a) is enum, which have two extra hidden params (name, index)
                if (ClassUtil.isEnumType(dc) && (paramCount == paramAnns.length + 2)) {
                    Annotation[][] old = paramAnns;
                    paramAnns = new Annotation[old.length+2][];
                    System.arraycopy(old, 0, paramAnns, 2, old.length);
                    resolvedAnnotations = collectAnnotations(paramAnns, null);
                } else if (dc.isMemberClass()) {
                    // (b) non-static inner classes, get implicit 'this' for parameter, not  annotation
                    if (paramCount == (paramAnns.length + 1)) {
                        // hack attack: prepend a null entry to make things match
                        Annotation[][] old = paramAnns;
                        paramAnns = new Annotation[old.length+1][];
                        System.arraycopy(old, 0, paramAnns, 1, old.length);
                        paramAnns[0] = NO_ANNOTATIONS;
                        resolvedAnnotations = collectAnnotations(paramAnns, null);
                    }
                }
                if (resolvedAnnotations == null) {
                    throw new IllegalStateException(String.format(
    "Internal error: constructor for %s has mismatch: %d parameters; %d sets of annotations",
    ctor.getDeclaringClass().getName(), paramCount, paramAnns.length));
                }
            } else {
                resolvedAnnotations = collectAnnotations(paramAnns,
                        (mixin == null) ? null : mixin.getParameterAnnotations());
            }
            return new AnnotatedConstructor(_typeContext, ctor.getConstructor(),
                    collectAnnotations(ctor, mixin), resolvedAnnotations);
        }
    
        protected AnnotatedMethod constructFactoryCreator(Method m,
                TypeResolutionContext typeResCtxt, Method mixin)
        {
            final int paramCount = m.getParameterTypes().length;
            if (_intr == null) { // when annotation processing is disabled
                return new AnnotatedMethod(typeResCtxt, m, _emptyAnnotationMap(),
                        _emptyAnnotationMaps(paramCount));
            }
            if (paramCount == 0) { // common enough we can slightly optimize
                return new AnnotatedMethod(typeResCtxt, m, collectAnnotations(m, mixin),
                        NO_ANNOTATION_MAPS);
            }
            return new AnnotatedMethod(typeResCtxt, m, collectAnnotations(m, mixin),
                    collectAnnotations(m.getParameterAnnotations(),
                            (mixin == null) ? null : mixin.getParameterAnnotations()));
        }
    
        private AnnotationMap[] collectAnnotations(Annotation[][] mainAnns, Annotation[][] mixinAnns) {
            if (_collectAnnotations) {
                final int count = mainAnns.length;
                AnnotationMap[] result = new AnnotationMap[count];
                for (int i = 0; i < count; ++i) {
                    AnnotationCollector c = collectAnnotations(AnnotationCollector.emptyCollector(),
                            mainAnns[i]);
                    if (mixinAnns != null) {
                        c = collectAnnotations(c, mixinAnns[i]);
                    }
                    result[i] = c.asAnnotationMap();
                }
                return result;
            }
            return NO_ANNOTATION_MAPS;
        }
    
        // // NOTE: these are only called when we know we have AnnotationIntrospector
    
        private AnnotationMap collectAnnotations(ClassUtil.Ctor main, ClassUtil.Ctor mixin) {
            if (_collectAnnotations) {
                AnnotationCollector c = collectAnnotations(main.getDeclaredAnnotations());
                if (mixin != null) {
                    c = collectAnnotations(c, mixin.getDeclaredAnnotations());
                }
                return c.asAnnotationMap();
            }
            return _emptyAnnotationMap();
        }
    
        private final AnnotationMap collectAnnotations(AnnotatedElement main, AnnotatedElement mixin) {
            AnnotationCollector c = collectAnnotations(main.getDeclaredAnnotations());
            if (mixin != null) {
                c = collectAnnotations(c, mixin.getDeclaredAnnotations());
            }
            return c.asAnnotationMap();
        }
    
        // for [databind#1005]: do not use or expose synthetic constructors
        private static boolean isIncludableConstructor(Constructor<?> c) {
            return !c.isSynthetic();
        }
    }
    

    com/fasterxml/jackson/databind/introspect/AnnotatedCreatorCollector.java

     

    ⇒ Jackson Annotations Source Code

    ⇐ Download and Install Jackson Binary Package

    ⇑ Downloading and Reviewing jackson-*.jar

    ⇑⇑ Jackson - Java JSON library

    2022-03-29, 32304👍, 0💬