All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.databind.deser.CreatorProperty Maven / Gradle / Ivy

There is a newer version: 2.17.0
Show newest version
package com.fasterxml.jackson.databind.deser;

import java.io.IOException;
import java.lang.annotation.Annotation;

import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.core.JsonParser;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.util.Annotations;
import com.fasterxml.jackson.databind.util.ClassUtil;

/**
 * This concrete sub-class implements property that is passed
 * via Creator (constructor or static factory method).
 * It is not a full-featured implementation in that its set method
 * should usually not be called for primary mutation -- instead, value must separately passed --
 * but some aspects are still needed (specifically, injection).
 *

* Note on injectable values: unlike with other mutators, where * deserializer and injecting are separate, here we treat the two as related * things. This is necessary to add proper priority, as well as to simplify * coordination. */ public class CreatorProperty extends SettableBeanProperty { private static final long serialVersionUID = 1L; /** * Placeholder that represents constructor parameter, when it is created * from actual constructor. * May be null when a synthetic instance is created. */ protected final AnnotatedParameter _annotated; /** * Id of value to inject, if value injection should be used for this parameter * (in addition to, or instead of, regular deserialization). * * @since 2.11 */ protected final JacksonInject.Value _injectableValue; /** * In special cases, when implementing "updateValue", we cannot use * constructors or factory methods, but have to fall back on using a * setter (or mutable field property). If so, this refers to that fallback * accessor. *

* Mutable only to allow setting after construction, but must be strictly * set before any use. * * @since 2.3 */ protected SettableBeanProperty _fallbackSetter; /** * @since 2.1 */ protected final int _creatorIndex; /** * Marker flag that may have to be set during construction, to indicate that * although property may have been constructed and added as a placeholder, * it represents something that should be ignored during deserialization. * This mostly concerns Creator properties which may not be easily deleted * during processing. * * @since 2.9.4 */ protected boolean _ignorable; /** * @since 2.11 */ protected CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName, TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedParameter param, int index, JacksonInject.Value injectable, PropertyMetadata metadata) { super(name, type, wrapperName, typeDeser, contextAnnotations, metadata); _annotated = param; _creatorIndex = index; _injectableValue = injectable; _fallbackSetter = null; } /** * @deprecated Since 2.11 use factory method instead */ @Deprecated // since 2.11 public CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName, TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedParameter param, int index, Object injectableValueId, PropertyMetadata metadata) { this(name, type, wrapperName, typeDeser, contextAnnotations, param, index, (injectableValueId == null) ? null : JacksonInject.Value.construct(injectableValueId, null), metadata); } /** * Factory method for creating {@link CreatorProperty} instances * * @param name Name of the logical property * @param type Type of the property, used to find deserializer * @param wrapperName Possible wrapper to use for logical property, if any * @param typeDeser Type deserializer to use for handling polymorphic type * information, if one is needed * @param contextAnnotations Contextual annotations (usually by class that * declares creator [constructor, factory method] that includes * this property) * @param param Representation of property, constructor or factory * method parameter; used for accessing annotations of the property * @param injectable Information about injectable value, if any * @param index Index of this property within creator invocation * * @since 2.11 */ public static CreatorProperty construct(PropertyName name, JavaType type, PropertyName wrapperName, TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedParameter param, int index, JacksonInject.Value injectable, PropertyMetadata metadata) { return new CreatorProperty(name, type, wrapperName, typeDeser, contextAnnotations, param, index, injectable, metadata); } /** * @since 2.3 */ protected CreatorProperty(CreatorProperty src, PropertyName newName) { super(src, newName); _annotated = src._annotated; _injectableValue = src._injectableValue; _fallbackSetter = src._fallbackSetter; _creatorIndex = src._creatorIndex; _ignorable = src._ignorable; } protected CreatorProperty(CreatorProperty src, JsonDeserializer deser, NullValueProvider nva) { super(src, deser, nva); _annotated = src._annotated; _injectableValue = src._injectableValue; _fallbackSetter = src._fallbackSetter; _creatorIndex = src._creatorIndex; _ignorable = src._ignorable; } @Override public SettableBeanProperty withName(PropertyName newName) { return new CreatorProperty(this, newName); } @Override public SettableBeanProperty withValueDeserializer(JsonDeserializer deser) { if (_valueDeserializer == deser) { return this; } // 07-May-2019, tatu: As per [databind#2303], must keep VD/NVP in-sync if they were NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider; return new CreatorProperty(this, deser, nvp); } @Override public SettableBeanProperty withNullProvider(NullValueProvider nva) { return new CreatorProperty(this, _valueDeserializer, nva); } @Override public void fixAccess(DeserializationConfig config) { if (_fallbackSetter != null) { _fallbackSetter.fixAccess(config); } } /** * NOTE: one exception to immutability, due to problems with CreatorProperty instances * being shared between Bean, separate PropertyBasedCreator * * @since 2.6 */ public void setFallbackSetter(SettableBeanProperty fallbackSetter) { _fallbackSetter = fallbackSetter; } @Override public void markAsIgnorable() { _ignorable = true; } @Override public boolean isIgnorable() { return _ignorable; } /* /********************************************************** /* Injection support /********************************************************** */ // 14-Apr-2020, tatu: Does not appear to be used so deprecated in 2.11.0, // to be removed from 2.12.0 // Method that can be called to locate value to be injected for this // property, if it is configured for this. @Deprecated // remove from 2.12 public Object findInjectableValue(DeserializationContext context, Object beanInstance) throws JsonMappingException { if (_injectableValue == null) { context.reportBadDefinition(ClassUtil.classOf(beanInstance), String.format("Property %s (type %s) has no injectable value id configured", ClassUtil.name(getName()), ClassUtil.classNameOf(this))); } return context.findInjectableValue(_injectableValue.getId(), this, beanInstance); // lgtm [java/dereferenced-value-may-be-null] } // 14-Apr-2020, tatu: Does not appear to be used so deprecated in 2.11.0, // to be removed from 2.12.0 // Method to find value to inject, and inject it to this property. @Deprecated // remove from 2.12 public void inject(DeserializationContext context, Object beanInstance) throws IOException { set(beanInstance, findInjectableValue(context, beanInstance)); } /* /********************************************************** /* BeanProperty impl /********************************************************** */ @Override public A getAnnotation(Class acls) { if (_annotated == null) { return null; } return _annotated.getAnnotation(acls); } @Override public AnnotatedMember getMember() { return _annotated; } @Override public int getCreatorIndex() { return _creatorIndex; } /* /********************************************************** /* Overridden methods, SettableBeanProperty /********************************************************** */ @Override public void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException { _verifySetter(); _fallbackSetter.set(instance, deserialize(p, ctxt)); } @Override public Object deserializeSetAndReturn(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException { _verifySetter(); return _fallbackSetter.setAndReturn(instance, deserialize(p, ctxt)); } @Override public void set(Object instance, Object value) throws IOException { _verifySetter(); _fallbackSetter.set(instance, value); } @Override public Object setAndReturn(Object instance, Object value) throws IOException { _verifySetter(); return _fallbackSetter.setAndReturn(instance, value); } @Override public PropertyMetadata getMetadata() { // 03-Jun-2019, tatu: Added as per [databind#2280] to support merge. // Not 100% sure why it would be needed (or fixes things) but... appears to. // Need to understand better in future as it seems like it should probably be // linked earlier during construction or something. // 22-Sep-2019, tatu: Was hoping [databind#2458] fixed this, too, but no such luck PropertyMetadata md = super.getMetadata(); if (_fallbackSetter != null) { return md.withMergeInfo(_fallbackSetter.getMetadata().getMergeInfo()); } return md; } // Perhaps counter-intuitively, ONLY creator properties return non-null id @Override public Object getInjectableValueId() { return (_injectableValue == null) ? null : _injectableValue.getId(); } @Override public boolean isInjectionOnly() { return (_injectableValue != null) && !_injectableValue.willUseInput(true); } // public boolean isInjectionOnly() { return false; } /* /********************************************************** /* Overridden methods, other /********************************************************** */ @Override public String toString() { return "[creator property, name "+ClassUtil.name(getName())+"; inject id '"+getInjectableValueId()+"']"; } /* /********************************************************** /* Internal helper methods /********************************************************** */ // since 2.9 private final void _verifySetter() throws IOException { if (_fallbackSetter == null) { _reportMissingSetter(null, null); } } // since 2.9 private void _reportMissingSetter(JsonParser p, DeserializationContext ctxt) throws IOException { final String msg = "No fallback setter/field defined for creator property "+ClassUtil.name(getName()); // Hmmmh. Should we return quietly (NOP), or error? // Perhaps better to throw an exception, since it's generally an error. if (ctxt != null ) { ctxt.reportBadDefinition(getType(), msg); } else { throw InvalidDefinitionException.from(p, msg, getType()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy