Esempio n. 1
0
  //  @Override
  public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property)
      throws JsonMappingException {
    /* 29-Sep-2012, tatu: Actually, we need to do much more contextual
     *    checking here since we finally know for sure the property,
     *    and it may have overrides
     */
    JsonSerializer<?> ser = null;
    JsonSerializer<?> keySer = null;

    // First: if we have a property, may have property-annotation overrides
    if (property != null) {
      AnnotatedMember m = property.getMember();
      if (m != null) {
        Object serDef;
        final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
        serDef = intr.findKeySerializer(m);
        if (serDef != null) {
          keySer = provider.serializerInstance(m, serDef);
        }
        serDef = intr.findContentSerializer(m);
        if (serDef != null) {
          ser = provider.serializerInstance(m, serDef);
        }
      }
    }
    if (ser == null) {
      ser = _valueSerializer;
    }
    if (ser == null) {
      // 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated,
      //   we can consider it a static case as well.
      if (_valueTypeIsStatic || hasContentTypeAnnotation(provider, property)) {
        ser = provider.findValueSerializer(_valueType, property);
      }
    } else if (ser instanceof ContextualSerializer) {
      ser = ((ContextualSerializer) ser).createContextual(provider, property);
    }
    if (keySer == null) {
      keySer = _keySerializer;
    }
    if (keySer == null) {
      keySer = provider.findKeySerializer(_keyType, property);
    } else if (keySer instanceof ContextualSerializer) {
      keySer = ((ContextualSerializer) keySer).createContextual(provider, property);
    }
    HashSet<String> ignored = this._ignoredEntries;
    AnnotationIntrospector intr = provider.getAnnotationIntrospector();
    if (intr != null && property != null) {
      String[] moreToIgnore = intr.findPropertiesToIgnore(property.getMember());
      if (moreToIgnore != null) {
        ignored = (ignored == null) ? new HashSet<String>() : new HashSet<String>(ignored);
        for (String str : moreToIgnore) {
          ignored.add(str);
        }
      }
    }
    return withResolved(property, keySer, ser, ignored);
  }
  public void testRootNameAccess() throws Exception {
    AnnotationIntrospector ai = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
    // If no @XmlRootElement, should get null (unless pkg has etc)
    assertNull(ai.findRootName(AnnotatedClass.construct(SimpleBean.class, ai, null)));
    // With @XmlRootElement, but no name, empty String
    PropertyName rootName =
        ai.findRootName(AnnotatedClass.construct(NamespaceBean.class, ai, null));
    assertNotNull(rootName);
    assertEquals("", rootName.getSimpleName());
    assertEquals("urn:class", rootName.getNamespace());

    // and otherwise explicit name
    rootName = ai.findRootName(AnnotatedClass.construct(RootNameBean.class, ai, null));
    assertNotNull(rootName);
    assertEquals("test", rootName.getSimpleName());
    assertNull(rootName.getNamespace());
  }
  /**
   * Method for getting ordered list of named Creator properties. Returns an empty list is none
   * found. If multiple Creator methods are defined, order between properties from different methods
   * is undefined; however, properties for each such Creator are ordered properly relative to each
   * other. For the usual case of just a single Creator, named properties are thus properly ordered.
   */
  public List<String> findCreatorPropertyNames() {
    List<String> names = null;

    for (int i = 0; i < 2; ++i) {
      List<? extends AnnotatedWithParams> l = (i == 0) ? getConstructors() : getFactoryMethods();
      for (AnnotatedWithParams creator : l) {
        int argCount = creator.getParameterCount();
        if (argCount < 1) continue;
        String name = _annotationIntrospector.findPropertyNameForParam(creator.getParameter(0));
        if (name == null) continue;
        if (names == null) {
          names = new ArrayList<String>();
        }
        names.add(name);
        for (int p = 1; p < argCount; ++p) {
          names.add(_annotationIntrospector.findPropertyNameForParam(creator.getParameter(p)));
        }
      }
    }
    if (names == null) {
      return Collections.emptyList();
    }
    return names;
  }
 /**
  * Method for locating all back-reference properties (setters, fields) bean has
  *
  * @since 1.6
  */
 public Map<String, AnnotatedMember> findBackReferenceProperties() {
   HashMap<String, AnnotatedMember> result = null;
   for (BeanPropertyDefinition property : _properties) {
     AnnotatedMember am = property.getMutator();
     if (am == null) {
       continue;
     }
     AnnotationIntrospector.ReferenceProperty refDef =
         _annotationIntrospector.findReferenceType(am);
     if (refDef != null && refDef.isBackReference()) {
       if (result == null) {
         result = new HashMap<String, AnnotatedMember>();
       }
       String refName = refDef.getName();
       if (result.put(refName, am) != null) {
         throw new IllegalArgumentException(
             "Multiple back-reference properties with name '" + refName + "'");
       }
     }
   }
   return result;
 }
  protected boolean isFactoryMethod(AnnotatedMethod am) {
    /* First: return type must be compatible with the introspected class
     * (i.e. allowed to be sub-class, although usually is the same
     * class)
     */
    Class<?> rt = am.getRawType();
    if (!getBeanClass().isAssignableFrom(rt)) {
      return false;
    }

    /* Also: must be a recognized factory method, meaning:
     * (a) marked with @JsonCreator annotation, or
     * (a) "valueOf" (at this point, need not be public)
     */
    if (_annotationIntrospector.hasCreatorAnnotation(am)) {
      return true;
    }
    if ("valueOf".equals(am.getName())) {
      return true;
    }
    return false;
  }
 /**
  * Method for determining whether null properties should be written out for a Bean of introspected
  * type. This is based on global feature (lowest priority, passed as argument) and per-class
  * annotation (highest priority).
  */
 public JsonSerialize.Inclusion findSerializationInclusion(JsonSerialize.Inclusion defValue) {
   if (_annotationIntrospector == null) {
     return defValue;
   }
   return _annotationIntrospector.findSerializationInclusion(_classInfo, defValue);
 }
  /**
   * Method called to figure out settable properties for the bean deserializer to use.
   *
   * <p>Note: designed to be overridable, and effort is made to keep interface similar between
   * versions.
   */
  protected void addBeanProps(
      DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder)
      throws JsonMappingException {
    final SettableBeanProperty[] creatorProps =
        builder.getValueInstantiator().getFromObjectArguments(ctxt.getConfig());

    // Things specified as "ok to ignore"? [JACKSON-77]
    AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
    boolean ignoreAny = false;
    {
      Boolean B = intr.findIgnoreUnknownProperties(beanDesc.getClassInfo());
      if (B != null) {
        ignoreAny = B.booleanValue();
        builder.setIgnoreUnknownProperties(ignoreAny);
      }
    }
    // Or explicit/implicit definitions?
    Set<String> ignored =
        ArrayBuilders.arrayToSet(intr.findPropertiesToIgnore(beanDesc.getClassInfo()));
    for (String propName : ignored) {
      builder.addIgnorable(propName);
    }
    // Also, do we have a fallback "any" setter?
    AnnotatedMethod anySetter = beanDesc.findAnySetter();
    if (anySetter != null) {
      builder.setAnySetter(constructAnySetter(ctxt, beanDesc, anySetter));
    }
    // NOTE: we do NOT add @JsonIgnore'd properties into blocked ones if there's any setter
    // Implicit ones via @JsonIgnore and equivalent?
    if (anySetter == null) {
      Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames();
      if (ignored2 != null) {
        for (String propName : ignored2) {
          // allow ignoral of similarly named JSON property, but do not force;
          // latter means NOT adding this to 'ignored':
          builder.addIgnorable(propName);
        }
      }
    }
    final boolean useGettersAsSetters =
        (ctxt.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS)
            && ctxt.isEnabled(MapperFeature.AUTO_DETECT_GETTERS));

    // Ok: let's then filter out property definitions
    List<BeanPropertyDefinition> propDefs =
        filterBeanProps(ctxt, beanDesc, builder, beanDesc.findProperties(), ignored);

    // After which we can let custom code change the set
    if (_factoryConfig.hasDeserializerModifiers()) {
      for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
        propDefs = mod.updateProperties(ctxt.getConfig(), beanDesc, propDefs);
      }
    }

    // At which point we still have all kinds of properties; not all with mutators:
    for (BeanPropertyDefinition propDef : propDefs) {
      SettableBeanProperty prop = null;
      if (propDef.hasConstructorParameter()) {
        /* [JACKSON-700] If property is passed via constructor parameter, we must
         *   handle things in special way. Not sure what is the most optimal way...
         *   for now, let's just call a (new) method in builder, which does nothing.
         */
        // but let's call a method just to allow custom builders to be aware...
        final String name = propDef.getName();
        for (SettableBeanProperty cp : creatorProps) {
          if (name.equals(cp.getName())) {
            prop = cp;
            break;
          }
        }
        if (prop == null) {
          throw ctxt.mappingException("Could not find creator property with name '" + name + "'");
        }
        builder.addCreatorProperty(prop);
        continue;
      }
      if (propDef.hasSetter()) {
        Type propertyType = propDef.getSetter().getGenericParameterType(0);
        prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
      } else if (propDef.hasField()) {
        Type propertyType = propDef.getField().getGenericType();
        prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
      } else if (useGettersAsSetters && propDef.hasGetter()) {
        /* As per [JACKSON-88], may also need to consider getters
         * for Map/Collection properties; but with lowest precedence
         */
        AnnotatedMethod getter = propDef.getGetter();
        // should only consider Collections and Maps, for now?
        Class<?> rawPropertyType = getter.getRawType();
        if (Collection.class.isAssignableFrom(rawPropertyType)
            || Map.class.isAssignableFrom(rawPropertyType)) {
          prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
        }
      }
      if (prop != null) {
        Class<?>[] views = propDef.findViews();
        if (views == null) {
          // one more twist: if default inclusion disabled, need to force empty set of views
          if (!ctxt.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
            views = NO_VIEWS;
          }
        }
        // one more thing before adding to builder: copy any metadata
        prop.setViews(views);
        builder.addProperty(prop);
      }
    }
  }
  @Override
  public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property)
      throws JsonMappingException {
    JsonSerializer<?> ser = null;
    JsonSerializer<?> keySer = null;
    final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
    final AnnotatedMember propertyAcc = (property == null) ? null : property.getMember();

    // First: if we have a property, may have property-annotation overrides
    if ((propertyAcc != null) && (intr != null)) {
      Object serDef = intr.findKeySerializer(propertyAcc);
      if (serDef != null) {
        keySer = provider.serializerInstance(propertyAcc, serDef);
      }
      serDef = intr.findContentSerializer(propertyAcc);
      if (serDef != null) {
        ser = provider.serializerInstance(propertyAcc, serDef);
      }
    }
    if (ser == null) {
      ser = _valueSerializer;
    }
    // [databind#124]: May have a content converter
    ser = findContextualConvertingSerializer(provider, property, ser);
    if (ser == null) {
      // 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated,
      //   we can consider it a static case as well.
      // 20-Aug-2013, tatu: Need to avoid trying to access serializer for java.lang.Object tho
      if (_valueTypeIsStatic && !_valueType.isJavaLangObject()) {
        ser = provider.findValueSerializer(_valueType, property);
      }
    }
    if (keySer == null) {
      keySer = _keySerializer;
    }
    if (keySer == null) {
      keySer = provider.findKeySerializer(_keyType, property);
    } else {
      keySer = provider.handleSecondaryContextualization(keySer, property);
    }
    Set<String> ignored = _ignoredEntries;
    boolean sortKeys = false;
    if ((intr != null) && (propertyAcc != null)) {
      JsonIgnoreProperties.Value ignorals = intr.findPropertyIgnorals(propertyAcc);
      if (ignorals != null) {
        Set<String> newIgnored = ignorals.findIgnoredForSerialization();
        if ((newIgnored != null) && !newIgnored.isEmpty()) {
          ignored = (ignored == null) ? new HashSet<String>() : new HashSet<String>(ignored);
          for (String str : newIgnored) {
            ignored.add(str);
          }
        }
      }
      Boolean b = intr.findSerializationSortAlphabetically(propertyAcc);
      sortKeys = (b != null) && b.booleanValue();
    }
    JsonFormat.Value format = findFormatOverrides(provider, property, Map.class);
    if (format != null) {
      Boolean B = format.getFeature(JsonFormat.Feature.WRITE_SORTED_MAP_ENTRIES);
      if (B != null) {
        sortKeys = B.booleanValue();
      }
    }
    MapSerializer mser = withResolved(property, keySer, ser, ignored, sortKeys);

    // [databind#307]: allow filtering
    if (property != null) {
      AnnotatedMember m = property.getMember();
      if (m != null) {
        Object filterId = intr.findFilterId(m);
        if (filterId != null) {
          mser = mser.withFilterId(filterId);
        }
      }
      JsonInclude.Value inclV = property.findPropertyInclusion(provider.getConfig(), null);
      if (inclV != null) {
        JsonInclude.Include incl = inclV.getContentInclusion();

        if (incl != JsonInclude.Include.USE_DEFAULTS) {
          Object valueToSuppress;
          boolean suppressNulls;
          switch (incl) {
            case NON_DEFAULT:
              valueToSuppress = BeanUtil.getDefaultValue(_valueType);
              suppressNulls = true;
              if (valueToSuppress != null) {
                if (valueToSuppress.getClass().isArray()) {
                  valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
                }
              }
              break;
            case NON_ABSENT:
              suppressNulls = true;
              valueToSuppress = _valueType.isReferenceType() ? MARKER_FOR_EMPTY : null;
              break;
            case NON_EMPTY:
              suppressNulls = true;
              valueToSuppress = MARKER_FOR_EMPTY;
              break;
            case CUSTOM:
              valueToSuppress = provider.includeFilterInstance(null, inclV.getContentFilter());
              if (valueToSuppress == null) { // is this legal?
                suppressNulls = true;
              } else {
                suppressNulls = provider.includeFilterSuppressNulls(valueToSuppress);
              }
              break;
            case NON_NULL:
              valueToSuppress = null;
              suppressNulls = true;
              break;
            case ALWAYS: // default
            default:
              valueToSuppress = null;
              // 30-Sep-2016, tatu: Should not need to check global flags here,
              //   if inclusion forced to be ALWAYS
              suppressNulls = false;
              break;
          }
          mser = mser.withContentInclusion(valueToSuppress, suppressNulls);
        }
      }
    }
    return mser;
  }