use of com.fasterxml.jackson.databind.introspect.AnnotatedMember in project jackson-databind by FasterXML.
the class StdDeserializer method findConvertingContentDeserializer.
/*
/**********************************************************
/* Helper methods for: deserializer construction
/**********************************************************
*/
/**
* Helper method that can be used to see if specified property has annotation
* indicating that a converter is to be used for contained values (contents
* of structured types; array/List/Map values)
*
* @param existingDeserializer (optional) configured content
* serializer if one already exists.
*
* @since 2.2
*/
protected JsonDeserializer<?> findConvertingContentDeserializer(DeserializationContext ctxt, BeanProperty prop, JsonDeserializer<?> existingDeserializer) throws JsonMappingException {
final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr != null && prop != null) {
AnnotatedMember member = prop.getMember();
if (member != null) {
Object convDef = intr.findDeserializationContentConverter(member);
if (convDef != null) {
Converter<Object, Object> conv = ctxt.converterInstance(prop.getMember(), convDef);
JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
if (existingDeserializer == null) {
existingDeserializer = ctxt.findContextualValueDeserializer(delegateType, prop);
}
return new StdDelegatingDeserializer<Object>(conv, delegateType, existingDeserializer);
}
}
}
return existingDeserializer;
}
use of com.fasterxml.jackson.databind.introspect.AnnotatedMember in project swagger-core by swagger-api.
the class ModelResolver method resolve.
public Model resolve(JavaType type, ModelConverterContext context, Iterator<ModelConverter> next) {
if (type.isEnumType() || PrimitiveType.fromType(type) != null) {
// We don't build models for primitive types
return null;
}
final BeanDescription beanDesc = _mapper.getSerializationConfig().introspect(type);
// Couple of possibilities for defining
String name = _typeName(type, beanDesc);
if ("Object".equals(name)) {
return new ModelImpl();
}
/**
* --Preventing parent/child hierarchy creation loops - Comment 1--
* Creating a parent model will result in the creation of child models. Creating a child model will result in
* the creation of a parent model, as per the second If statement following this comment.
*
* By checking whether a model has already been resolved (as implemented below), loops of parents creating
* children and children creating parents can be short-circuited. This works because currently the
* ModelConverterContextImpl will return null for a class that already been processed, but has not yet been
* defined. This logic works in conjunction with the early immediate definition of model in the context
* implemented later in this method (See "Preventing parent/child hierarchy creation loops - Comment 2") to
* prevent such
*/
Model resolvedModel = context.resolve(type.getRawClass());
if (resolvedModel != null) {
if (!(resolvedModel instanceof ModelImpl || resolvedModel instanceof ComposedModel) || (resolvedModel instanceof ModelImpl && ((ModelImpl) resolvedModel).getName().equals(name))) {
return resolvedModel;
} else if (resolvedModel instanceof ComposedModel) {
Model childModel = ((ComposedModel) resolvedModel).getChild();
if (childModel != null && (!(childModel instanceof ModelImpl) || ((ModelImpl) childModel).getName().equals(name))) {
return resolvedModel;
}
}
}
final ModelImpl model = new ModelImpl().type(ModelImpl.OBJECT).name(name).description(_description(beanDesc.getClassInfo()));
if (!type.isContainerType()) {
// define the model here to support self/cyclic referencing of models
context.defineModel(name, model, type, null);
}
if (type.isContainerType()) {
// We treat collections as primitive types, just need to add models for values (if any)
context.resolve(type.getContentType());
return null;
}
// if XmlRootElement annotation, construct an Xml object and attach it to the model
XmlRootElement rootAnnotation = beanDesc.getClassAnnotations().get(XmlRootElement.class);
if (rootAnnotation != null && !"".equals(rootAnnotation.name()) && !"##default".equals(rootAnnotation.name())) {
LOGGER.debug("{}", rootAnnotation);
Xml xml = new Xml().name(rootAnnotation.name());
if (rootAnnotation.namespace() != null && !"".equals(rootAnnotation.namespace()) && !"##default".equals(rootAnnotation.namespace())) {
xml.namespace(rootAnnotation.namespace());
}
model.xml(xml);
}
final XmlAccessorType xmlAccessorTypeAnnotation = beanDesc.getClassAnnotations().get(XmlAccessorType.class);
// see if @JsonIgnoreProperties exist
Set<String> propertiesToIgnore = new HashSet<String>();
JsonIgnoreProperties ignoreProperties = beanDesc.getClassAnnotations().get(JsonIgnoreProperties.class);
if (ignoreProperties != null) {
propertiesToIgnore.addAll(Arrays.asList(ignoreProperties.value()));
}
final ApiModel apiModel = beanDesc.getClassAnnotations().get(ApiModel.class);
String disc = (apiModel == null) ? "" : apiModel.discriminator();
if (apiModel != null && StringUtils.isNotEmpty(apiModel.reference())) {
model.setReference(apiModel.reference());
}
if (disc.isEmpty()) {
// longer method would involve AnnotationIntrospector.findTypeResolver(...) but:
JsonTypeInfo typeInfo = beanDesc.getClassAnnotations().get(JsonTypeInfo.class);
if (typeInfo != null) {
disc = typeInfo.property();
}
}
if (!disc.isEmpty()) {
model.setDiscriminator(disc);
}
List<Property> props = new ArrayList<Property>();
for (BeanPropertyDefinition propDef : beanDesc.findProperties()) {
Property property = null;
String propName = propDef.getName();
Annotation[] annotations = null;
// it's ugly but gets around https://github.com/swagger-api/swagger-core/issues/415
if (propDef.getPrimaryMember() != null) {
java.lang.reflect.Member member = propDef.getPrimaryMember().getMember();
if (member != null) {
String altName = member.getName();
if (altName != null) {
final int length = altName.length();
for (String prefix : Arrays.asList("get", "is")) {
final int offset = prefix.length();
if (altName.startsWith(prefix) && length > offset && !Character.isUpperCase(altName.charAt(offset))) {
propName = altName;
break;
}
}
}
}
}
PropertyMetadata md = propDef.getMetadata();
boolean hasSetter = false, hasGetter = false;
try {
if (propDef.getSetter() == null) {
hasSetter = false;
} else {
hasSetter = true;
}
} catch (IllegalArgumentException e) {
//com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder would throw IllegalArgumentException
// if there are overloaded setters. If we only want to know whether a set method exists, suppress the exception
// is reasonable.
// More logs might be added here
hasSetter = true;
}
if (propDef.getGetter() != null) {
JsonProperty pd = propDef.getGetter().getAnnotation(JsonProperty.class);
if (pd != null) {
hasGetter = true;
}
}
Boolean isReadOnly = null;
if (!hasSetter & hasGetter) {
isReadOnly = Boolean.TRUE;
} else {
isReadOnly = Boolean.FALSE;
}
final AnnotatedMember member = propDef.getPrimaryMember();
Boolean allowEmptyValue = null;
if (member != null && !ignore(member, xmlAccessorTypeAnnotation, propName, propertiesToIgnore)) {
List<Annotation> annotationList = new ArrayList<Annotation>();
for (Annotation a : member.annotations()) {
annotationList.add(a);
}
annotations = annotationList.toArray(new Annotation[annotationList.size()]);
ApiModelProperty mp = member.getAnnotation(ApiModelProperty.class);
if (mp != null && mp.readOnly()) {
isReadOnly = mp.readOnly();
}
if (mp != null && mp.allowEmptyValue()) {
allowEmptyValue = mp.allowEmptyValue();
} else {
allowEmptyValue = null;
}
JavaType propType = member.getType(beanDesc.bindingsForBeanType());
// allow override of name from annotation
if (mp != null && !mp.name().isEmpty()) {
propName = mp.name();
}
if (mp != null && !mp.dataType().isEmpty()) {
String or = mp.dataType();
JavaType innerJavaType = null;
LOGGER.debug("overriding datatype from {} to {}", propType, or);
if (or.toLowerCase().startsWith("list[")) {
String innerType = or.substring(5, or.length() - 1);
ArrayProperty p = new ArrayProperty();
Property primitiveProperty = PrimitiveType.createProperty(innerType);
if (primitiveProperty != null) {
p.setItems(primitiveProperty);
} else {
innerJavaType = getInnerType(innerType);
p.setItems(context.resolveProperty(innerJavaType, annotations));
}
property = p;
} else if (or.toLowerCase().startsWith("map[")) {
int pos = or.indexOf(",");
if (pos > 0) {
String innerType = or.substring(pos + 1, or.length() - 1);
MapProperty p = new MapProperty();
Property primitiveProperty = PrimitiveType.createProperty(innerType);
if (primitiveProperty != null) {
p.setAdditionalProperties(primitiveProperty);
} else {
innerJavaType = getInnerType(innerType);
p.setAdditionalProperties(context.resolveProperty(innerJavaType, annotations));
}
property = p;
}
} else {
Property primitiveProperty = PrimitiveType.createProperty(or);
if (primitiveProperty != null) {
property = primitiveProperty;
} else {
innerJavaType = getInnerType(or);
property = context.resolveProperty(innerJavaType, annotations);
}
}
if (innerJavaType != null) {
context.resolve(innerJavaType);
}
}
// no property from override, construct from propType
if (property == null) {
if (mp != null && StringUtils.isNotEmpty(mp.reference())) {
property = new RefProperty(mp.reference());
} else if (member.getAnnotation(JsonIdentityInfo.class) != null) {
property = GeneratorWrapper.processJsonIdentity(propType, context, _mapper, member.getAnnotation(JsonIdentityInfo.class), member.getAnnotation(JsonIdentityReference.class));
}
if (property == null) {
JsonUnwrapped uw = member.getAnnotation(JsonUnwrapped.class);
if (uw != null && uw.enabled()) {
handleUnwrapped(props, context.resolve(propType), uw.prefix(), uw.suffix());
} else {
property = context.resolveProperty(propType, annotations);
}
}
}
if (property != null) {
property.setName(propName);
if (mp != null && !mp.access().isEmpty()) {
property.setAccess(mp.access());
}
Boolean required = md.getRequired();
if (required != null) {
property.setRequired(required);
}
String description = _intr.findPropertyDescription(member);
if (description != null && !"".equals(description)) {
property.setDescription(description);
}
Integer index = _intr.findPropertyIndex(member);
if (index != null) {
property.setPosition(index);
}
property.setDefault(_findDefaultValue(member));
property.setExample(_findExampleValue(member));
property.setReadOnly(_findReadOnly(member));
if (allowEmptyValue != null) {
property.setAllowEmptyValue(allowEmptyValue);
}
if (property.getReadOnly() == null) {
if (isReadOnly) {
property.setReadOnly(isReadOnly);
}
}
if (mp != null) {
final AllowableValues allowableValues = AllowableValuesUtils.create(mp.allowableValues());
if (allowableValues != null) {
final Map<PropertyBuilder.PropertyId, Object> args = allowableValues.asPropertyArguments();
PropertyBuilder.merge(property, args);
}
}
JAXBAnnotationsHelper.apply(member, property);
applyBeanValidatorAnnotations(property, annotations);
props.add(property);
}
}
}
Collections.sort(props, getPropertyComparator());
Map<String, Property> modelProps = new LinkedHashMap<String, Property>();
for (Property prop : props) {
modelProps.put(prop.getName(), prop);
}
model.setProperties(modelProps);
/**
* --Preventing parent/child hierarchy creation loops - Comment 2--
* Creating a parent model will result in the creation of child models, as per the first If statement following
* this comment. Creating a child model will result in the creation of a parent model, as per the second If
* statement following this comment.
*
* The current model must be defined in the context immediately. This done to help prevent repeated
* loops where parents create children and children create parents when a hierarchy is present. This logic
* works in conjunction with the "early checking" performed earlier in this method
* (See "Preventing parent/child hierarchy creation loops - Comment 1"), to prevent repeated creation loops.
*
*
* As an aside, defining the current model in the context immediately also ensures that child models are
* available for modification by resolveSubtypes, when their parents are created.
*/
Class<?> currentType = type.getRawClass();
context.defineModel(name, model, currentType, null);
/**
* This must be done after model.setProperties so that the model's set
* of properties is available to filter from any subtypes
**/
if (!resolveSubtypes(model, beanDesc, context)) {
model.setDiscriminator(null);
}
if (apiModel != null) {
/**
* Check if the @ApiModel annotation has a parent property containing a value that should not be ignored
*/
Class<?> parentClass = apiModel.parent();
if (parentClass != null && !parentClass.equals(Void.class) && !this.shouldIgnoreClass(parentClass)) {
JavaType parentType = _mapper.constructType(parentClass);
final BeanDescription parentBeanDesc = _mapper.getSerializationConfig().introspect(parentType);
/**
* Retrieve all the sub-types of the parent class and ensure that the current type is one of those types
*/
boolean currentTypeIsParentSubType = false;
List<NamedType> subTypes = _intr.findSubtypes(parentBeanDesc.getClassInfo());
if (subTypes != null) {
for (NamedType subType : subTypes) {
if (subType.getType().equals(currentType)) {
currentTypeIsParentSubType = true;
break;
}
}
}
/**
Retrieve the subTypes from the parent class @ApiModel annotation and ensure that the current type
is one of those types.
*/
boolean currentTypeIsParentApiModelSubType = false;
final ApiModel parentApiModel = parentBeanDesc.getClassAnnotations().get(ApiModel.class);
if (parentApiModel != null) {
Class<?>[] apiModelSubTypes = parentApiModel.subTypes();
if (apiModelSubTypes != null) {
for (Class<?> subType : apiModelSubTypes) {
if (subType.equals(currentType)) {
currentTypeIsParentApiModelSubType = true;
break;
}
}
}
}
/**
If the current type is a sub-type of the parent class and is listed in the subTypes property of the
parent class @ApiModel annotation, then do the following:
1. Resolve the model for the parent class. This will result in the parent model being created, and the
current child model being updated to be a ComposedModel referencing the parent.
2. Resolve and return the current child type again. This will return the new ComposedModel from the
context, which was created in step 1 above. Admittedly, there is a small chance that this may result
in a stack overflow, if the context does not correctly cache the model for the current type. However,
as context caching is assumed elsewhere to avoid cyclical model creation, this was deemed to be
sufficient.
*/
if (currentTypeIsParentSubType && currentTypeIsParentApiModelSubType) {
context.resolve(parentClass);
return context.resolve(currentType);
}
}
}
return model;
}
use of com.fasterxml.jackson.databind.introspect.AnnotatedMember in project jackson-databind by FasterXML.
the class BeanSerializerBase method createContextual.
@SuppressWarnings("incomplete-switch")
@Override
public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException {
final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
final AnnotatedMember accessor = (property == null || intr == null) ? null : property.getMember();
final SerializationConfig config = provider.getConfig();
// Let's start with one big transmutation: Enums that are annotated
// to serialize as Objects may want to revert
JsonFormat.Value format = findFormatOverrides(provider, property, handledType());
JsonFormat.Shape shape = null;
if ((format != null) && format.hasShape()) {
shape = format.getShape();
// or, alternatively, asked to revert "back to" other representations...
if ((shape != JsonFormat.Shape.ANY) && (shape != _serializationShape)) {
if (_handledType.isEnum()) {
switch(shape) {
case STRING:
case NUMBER:
case NUMBER_INT:
// 12-Oct-2014, tatu: May need to introspect full annotations... but
// for now, just do class ones
BeanDescription desc = config.introspectClassAnnotations(_beanType);
JsonSerializer<?> ser = EnumSerializer.construct(_beanType.getRawClass(), provider.getConfig(), desc, format);
return provider.handlePrimaryContextualization(ser, property);
}
// 16-Oct-2016, tatu: Ditto for `Map`, `Map.Entry` subtypes
} else if (shape == JsonFormat.Shape.NATURAL) {
if (_beanType.isMapLikeType() && Map.class.isAssignableFrom(_handledType)) {
;
} else if (Map.Entry.class.isAssignableFrom(_handledType)) {
JavaType mapEntryType = _beanType.findSuperType(Map.Entry.class);
JavaType kt = mapEntryType.containedTypeOrUnknown(0);
JavaType vt = mapEntryType.containedTypeOrUnknown(1);
// 16-Oct-2016, tatu: could have problems with type handling, as we do not
// see if "static" typing is needed, nor look for `TypeSerializer` yet...
JsonSerializer<?> ser = new MapEntrySerializer(_beanType, kt, vt, false, null, property);
return provider.handlePrimaryContextualization(ser, property);
}
}
}
}
ObjectIdWriter oiw = _objectIdWriter;
Set<String> ignoredProps = null;
Object newFilterId = null;
// Then we may have an override for Object Id
if (accessor != null) {
JsonIgnoreProperties.Value ignorals = intr.findPropertyIgnorals(accessor);
if (ignorals != null) {
ignoredProps = ignorals.findIgnoredForSerialization();
}
ObjectIdInfo objectIdInfo = intr.findObjectIdInfo(accessor);
if (objectIdInfo == null) {
// no ObjectId override, but maybe ObjectIdRef?
if (oiw != null) {
objectIdInfo = intr.findObjectReferenceInfo(accessor, new ObjectIdInfo(NAME_FOR_OBJECT_REF, null, null, null));
oiw = _objectIdWriter.withAlwaysAsId(objectIdInfo.getAlwaysAsId());
}
} else {
/* Ugh: mostly copied from BeanSerializerBase: but can't easily
* change it to be able to move to SerializerProvider (where it
* really belongs)
*/
// 2.1: allow modifications by "id ref" annotations as well:
objectIdInfo = intr.findObjectReferenceInfo(accessor, objectIdInfo);
ObjectIdGenerator<?> gen;
Class<?> implClass = objectIdInfo.getGeneratorType();
JavaType type = provider.constructType(implClass);
JavaType idType = provider.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0];
// Property-based generator is trickier
if (implClass == ObjectIdGenerators.PropertyGenerator.class) {
// most special one, needs extra work
String propName = objectIdInfo.getPropertyName().getSimpleName();
BeanPropertyWriter idProp = null;
for (int i = 0, len = _props.length; ; ++i) {
if (i == len) {
throw new IllegalArgumentException("Invalid Object Id definition for " + _handledType.getName() + ": can not find property with name '" + propName + "'");
}
BeanPropertyWriter prop = _props[i];
if (propName.equals(prop.getName())) {
idProp = prop;
/* Let's force it to be the first property to output
* (although it may still get rearranged etc)
*/
if (i > 0) {
// note: must shuffle both regular properties and filtered
System.arraycopy(_props, 0, _props, 1, i);
_props[0] = idProp;
if (_filteredProps != null) {
BeanPropertyWriter fp = _filteredProps[i];
System.arraycopy(_filteredProps, 0, _filteredProps, 1, i);
_filteredProps[0] = fp;
}
}
break;
}
}
idType = idProp.getType();
gen = new PropertyBasedObjectIdGenerator(objectIdInfo, idProp);
oiw = ObjectIdWriter.construct(idType, (PropertyName) null, gen, objectIdInfo.getAlwaysAsId());
} else {
// other types need to be simpler
gen = provider.objectIdGeneratorInstance(accessor, objectIdInfo);
oiw = ObjectIdWriter.construct(idType, objectIdInfo.getPropertyName(), gen, objectIdInfo.getAlwaysAsId());
}
}
// Or change Filter Id in use?
Object filterId = intr.findFilterId(accessor);
if (filterId != null) {
// but only consider case of adding a new filter id (no removal via annotation)
if (_propertyFilterId == null || !filterId.equals(_propertyFilterId)) {
newFilterId = filterId;
}
}
}
// either way, need to resolve serializer:
BeanSerializerBase contextual = this;
if (oiw != null) {
JsonSerializer<?> ser = provider.findValueSerializer(oiw.idType, property);
oiw = oiw.withSerializer(ser);
if (oiw != _objectIdWriter) {
contextual = contextual.withObjectIdWriter(oiw);
}
}
// And possibly add more properties to ignore
if ((ignoredProps != null) && !ignoredProps.isEmpty()) {
contextual = contextual.withIgnorals(ignoredProps);
}
if (newFilterId != null) {
contextual = contextual.withFilterId(newFilterId);
}
if (shape == null) {
shape = _serializationShape;
}
// last but not least; may need to transmute into as-array serialization
if (shape == JsonFormat.Shape.ARRAY) {
return contextual.asArraySerializer();
}
return contextual;
}
use of com.fasterxml.jackson.databind.introspect.AnnotatedMember in project jackson-databind by FasterXML.
the class BeanSerializerBase method findConvertingSerializer.
/**
* Helper method that can be used to see if specified property is annotated
* to indicate use of a converter for property value (in case of container types,
* it is container type itself, not key or content type).
*
* @since 2.2
*/
protected JsonSerializer<Object> findConvertingSerializer(SerializerProvider provider, BeanPropertyWriter prop) throws JsonMappingException {
final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
if (intr != null) {
AnnotatedMember m = prop.getMember();
if (m != null) {
Object convDef = intr.findSerializationConverter(m);
if (convDef != null) {
Converter<Object, Object> conv = provider.converterInstance(prop.getMember(), convDef);
JavaType delegateType = conv.getOutputType(provider.getTypeFactory());
// [databind#731]: Should skip if nominally java.lang.Object
JsonSerializer<?> ser = delegateType.isJavaLangObject() ? null : provider.findValueSerializer(delegateType, prop);
return new StdDelegatingSerializer(conv, delegateType, ser);
}
}
}
return null;
}
use of com.fasterxml.jackson.databind.introspect.AnnotatedMember in project jackson-databind by FasterXML.
the class MapEntrySerializer method createContextual.
@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) {
// 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);
}
Object valueToSuppress = _suppressableValue;
boolean suppressNulls = _suppressNulls;
if (property != null) {
JsonInclude.Value inclV = property.findPropertyInclusion(provider.getConfig(), null);
if (inclV != null) {
JsonInclude.Include incl = inclV.getContentInclusion();
if (incl != JsonInclude.Include.USE_DEFAULTS) {
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;
// default
case ALWAYS:
default:
valueToSuppress = null;
// 30-Sep-2016, tatu: Should not need to check global flags here,
// if inclusion forced to be ALWAYS
suppressNulls = false;
break;
}
}
}
}
MapEntrySerializer mser = withResolved(property, keySer, ser, valueToSuppress, suppressNulls);
// but note: no (full) filtering or sorting (unlike Maps)
return mser;
}
Aggregations