@Override public List<BeanPropertyDefinition> updateProperties( DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) { final AnnotationIntrospector intr = config.getAnnotationIntrospector(); int changed = 0; for (int i = 0, len = propDefs.size(); i < len; ++i) { BeanPropertyDefinition prop = propDefs.get(i); AnnotatedMember acc = prop.getAccessor(); // should not be null, but just in case: if (acc == null) { continue; } // first: do we need to handle wrapping (for Lists)? QName wrapperName = AnnotationUtil.findWrapperName(intr, acc); if (wrapperName != null) { String localName = wrapperName.getLocalPart(); if ((localName != null && localName.length() >= 0) && !localName.equals(prop.getName())) { // make copy-on-write as necessary if (changed == 0) { propDefs = new ArrayList<BeanPropertyDefinition>(propDefs); } ++changed; propDefs.set(i, prop.withName(localName)); continue; } } else { /* If not, how about "as text" unwrapping? Such properties * are exposed as values of 'unnamed' fields; so one way to * map them is to rename property to have name ""... (and * hope this does not break other parts...) */ Boolean b = AnnotationUtil.findIsTextAnnotation(intr, acc); if (b != null && b.booleanValue()) { // unwrapped properties will appear as 'unnamed' (empty String) propDefs.set(i, prop.withName("")); continue; } } } return propDefs; }
// [Issue#381] public void testSingleElementArray() throws Exception { final int intTest = 932832; final double doubleTest = 32.3234; final long longTest = 2374237428374293423L; final short shortTest = (short) intTest; final float floatTest = 84.3743f; final byte byteTest = (byte) 43; final char charTest = 'c'; final ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); final int intValue = mapper.readValue(asArray(intTest), Integer.TYPE); assertEquals(intTest, intValue); final Integer integerWrapperValue = mapper.readValue(asArray(Integer.valueOf(intTest)), Integer.class); assertEquals(Integer.valueOf(intTest), integerWrapperValue); final double doubleValue = mapper.readValue(asArray(doubleTest), Double.class); assertEquals(doubleTest, doubleValue); final Double doubleWrapperValue = mapper.readValue(asArray(Double.valueOf(doubleTest)), Double.class); assertEquals(Double.valueOf(doubleTest), doubleWrapperValue); final long longValue = mapper.readValue(asArray(longTest), Long.TYPE); assertEquals(longTest, longValue); final Long longWrapperValue = mapper.readValue(asArray(Long.valueOf(longTest)), Long.class); assertEquals(Long.valueOf(longTest), longWrapperValue); final short shortValue = mapper.readValue(asArray(shortTest), Short.TYPE); assertEquals(shortTest, shortValue); final Short shortWrapperValue = mapper.readValue(asArray(Short.valueOf(shortTest)), Short.class); assertEquals(Short.valueOf(shortTest), shortWrapperValue); final float floatValue = mapper.readValue(asArray(floatTest), Float.TYPE); assertEquals(floatTest, floatValue); final Float floatWrapperValue = mapper.readValue(asArray(Float.valueOf(floatTest)), Float.class); assertEquals(Float.valueOf(floatTest), floatWrapperValue); final byte byteValue = mapper.readValue(asArray(byteTest), Byte.TYPE); assertEquals(byteTest, byteValue); final Byte byteWrapperValue = mapper.readValue(asArray(Byte.valueOf(byteTest)), Byte.class); assertEquals(Byte.valueOf(byteTest), byteWrapperValue); final char charValue = mapper.readValue(asArray(quote(String.valueOf(charTest))), Character.TYPE); assertEquals(charTest, charValue); final Character charWrapperValue = mapper.readValue(asArray(quote(String.valueOf(charTest))), Character.class); assertEquals(Character.valueOf(charTest), charWrapperValue); final boolean booleanTrueValue = mapper.readValue(asArray(true), Boolean.TYPE); assertTrue(booleanTrueValue); final boolean booleanFalseValue = mapper.readValue(asArray(false), Boolean.TYPE); assertFalse(booleanFalseValue); final Boolean booleanWrapperTrueValue = mapper.readValue(asArray(Boolean.valueOf(true)), Boolean.class); assertEquals(Boolean.TRUE, booleanWrapperTrueValue); }
/** * 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; }