-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Jackson Release 2.8
Version 2.8 development is nearing the first Release Candidate, as of June 1st, 2016.
First official version of https://github.com/FasterXML/jackson-dataformat-properties!
- Support: following modules may become "unsupported" if no maintainers are found:
- Hibernate
- JSON Schema
(note: a new owner was found for Scala module so it is not at risk)
All language features (and Throwable.addSuppressed() for try-catch) of Java 7 will become available for components other than jackson-annotations and jackson-core (streaming).
This means that for Android 4, API-level 19 (Android 4.4?) is needed (see this SO entry for details)
Despite initial plans, 2.8 does NOT contain any of Java 8 features embedded, partly due to problems ensuring that Creator handling works without backwards compatibility issues. Creator handling is hoped to be rewritten in 2.9, at which point inclusion could be reconsidered.
One major improvement area that was not tackled in 2.7 was the ability to specify per-type configuration settings for things like formatting and serialization inclusion, such that settings:
- Do override global defaults (such as default date format)
- Are based on declared property type
- May be further overridden by per-property annotations (direct or mix-ins)
Some examples include:
- Ability to specify
DateFormatto use only forjava.util.Datebut not Java 8 or Joda date types (or vice versa) - Ability to specify that every
String[]valued property allows "deserialize single value as Array" - Inclusion criteria for POJO type
MyTypeso that properties with that type are not included if they arenull - Enable "ignore unknown properties" for
LooseType-valued properties - Specify
InternalTypeas "ignored type", similar to having been annotated with@JsonIgnoreType
Chosen implementation mechanism is the new "type config overrides" mechanism, which may be used like so
ObjectMapper mapper = ...;
mapper.configOverride(Wrapped.class).setIsIgnoredType(true);to handle the last listed use case: in this case, make sure that all properties of type Wrapped will be excluded from serialization and deserialization.
Other examples include:
mapper.configOverride(String[].class).setFormat(JsonFormat.Value.empty()
.withFeature(JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED));This new "configuration override" mechanism supports a subset of Class annotations, and does not yet have anything for per-property annotations. It should, however, be relatively straight-forward to extend similar approach to overrides of actual property. Loose equivalence is included for following annotation types:
@JsonFormat@JsonInclude@JsonIgnoreType@JsonIgnoreProperties
(and related changes in DeserializationContext)
One are of improvement that was added recently (and not "inherited" from 2.7) is that of explicit error recovery. Jackson already had pluggable handler, DeserializationProblemHandler for application code to use,
but it only contained one handling method (handleUnknownProperty) and was only capable of recovering from that one type of issue.
With 2.8 things were radically refactored to add following handler methods:
-
handleWeirdKey: called when key forMapvalued property can not be mapped to expected key type -
handleWeirdStringValue: called when specific JSON String can not be deserialized into value, in cases where other String values are acceptable -
handleWeirdNumberValue: called when specific JSON Number can not be deserialized into value, in cases where other String values are acceptable -
handleUnexpectedToken: called when specificJsonTokenis not of supported type for target Java type (likeSTART_ARRAYfor Java String -
handleInstantiationProblem/handleMissingInstantiator: when either call via constructor/factory method failed, or no instantiator was available -
handleUnknownTypeId: called when Type Id (for polymorphic deserialization) can not be converted (missing mapping, for example)
These methods will get invoked via DeserializationContext that has similarly named methods that are called by actual deserializers; support for handling therefore requires some co-operation of deserializer implementations.
Handler methods may try to recover from the failure (either for full processing, or to keep track of all failure types), or provide more meaningful exception messages based on contextual information. It is possible that with future versions we may try to add some form of "do not fail on first problem", aggregation of multiple failures, but with 2.8 this is just foundational support for building such support externally.
One potentially significant improvement is possibility of using java.io.DataInput as input source.
Due to strict limitations with look-ahead, this input source can only be supported for some formats;
and with 2.8 following formats now support it:
- JSON
In addition it seems plausible that at least following format backends may be retrofitted if there is demand:
- Avro
- CBOR
- Smile
- XML (but only theoretically as this requires XML parser support)
As to others, following are unlikely to be supported due to format limitations:
- Protobuf (no framing for main-level records)
- CSV, Properties, YAML (similarly open-ended, no end marker)
As opposed to DataInput, adding ability to write using DataOutput is trivial, so support has been added for all backends
Since some binary data formats have optimized handling for things like packed numeric arrays, a small set of extension methods (name writeArray()) were added in JsonGenerator, along with default implementation that simply delegates to matching write methods.
But for a small set of dataformats:
- CBOR
- Protobuf
- Smile
additional support was included to make actual operation significantly more efficient (and in case of CBOR, also uses definite count arrays instead of start/end marker). These methods may be called directly (when working directly on Streaming API), but they are also used for properties with value of:
int[]long[]double[]
In addition it would be possible to add explicit support for Avro backend; and if/when CBOR specification is augmented with support for "packed arrays", jackson-dataformat-cbor may be augmented to make use of such format improvement.
Version 2.7 version had ambitious goals, but many of features originally planned had to be postponed to ensure that the main features started could be completed in time. Some of these features did not make it into 2.8 either; here's an overview.
Currently all property values are newly created "virgin" Objects. But sometimes it would be useful to see if property already had a default value (set by parent POJO in constructor, typically), and if so, modify that value.
While it is possible to use @JsonInclude on properties, all choices use pre-defined rules; or, in case of NON_EMPTY (and by extension, NON_ABSENT) require matching JsonSerializer.isEmpty(...) to be implemented.
But it should be possible to have a simpler external exclusion handling. This could work by adding support for something like:
public class POJO {
@JsonInclude(value=Include.MATCHING, matcher=MyMatcher.class)
public Value value;where an instance of MyMatcher will be created, and for each property value, MyMatchr.equals() is called to see if value matches: if it does (return true), value will be included; if not (false), it will be excluded.
Such an approach has the main benefit that since Object.equals() is defined for all types, no new types (interface, class) are needed. We can also easily use something like Void.class as the default value.
There are drawbacks as well:
- No context object can be passed so determination must be context-free (note: annotation types also can not refer to
DatabindContext, so context, if any, would need to be untyped as well) - Use of
equals()is an abuse of semantics of the method.
Another approach would be to just create a new interface to fix the issues. Perhaps that makes more sense.
One of the things that has turned out problematic is resolution of Object References via Object Ids. There are a few improvements that could be considered:
- Allow pre-defining set of Object Id to instance mappings
- Allow custom resolution of Object Id references to instances
Although the hope was to add support for "annotation-less" constructors in 2.6, via implied naming, it turned out that there was one remaining big stumbling block: too-late discovery of "creator-capable" constructors.
Basically while it is possible to detect constructors that may act as Creators, due to all parameters having implicit names, this detection happens too late in processing: currently candidate properties (getters, setters, fields, constructor parameters) are collected first, and during this phase, only explicitly annotation constructors are considered. At a later point, all constructors are scanned again, and they are matched to properties that are backed by constructor. But "implied" creators found at this point can not be matched to properties, since they were not constructed during initial pass.
So discovery needs to be rewritten to either make implied-creator detection happen earlier altogether, or to speculative add properties from constructors first, and then decide which constructor, if any, is the primary; properties attached to other constructors will then be trimmed. Either way could potentially work; neither is trivially easy to implement.
Protobuf support added in 2.6 was planned to allow 3 methods for defining protoc schema:
- Read from an external representation (File, String)
- Generate from POJO
- Create programmatically
but due to schedule, only (1) is supported. We should add missing modes.
-
#83: Add
@JsonEnumDefaultValuefor indicating default enum choice if no real match found
-
#117: Add
JsonParser.Feature.ALLOW_MISSING_VALUESto support for missing values -
#253: Add
JsonGenerator. writeEmbeddedObject()to allow writes of opaque native types -
#254: Add
JsonParser.finishToken()to force full, non-lazy reading of current token
-
#621: Allow definition of "ignorable types" without annotation (using
Mapper.configOverride(type).setIsIgnoredType(true) -
#903: Add
JsonGeneratorreference toSerializerProvider -
#931: Add new method in
Deserializers.Baseto supportReferenceType -
#960:
@JsonCreatornot working on a factory with no arguments for an enum type -
#990: Allow failing on
nullvalues for creator (addDeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES) - #1017: Add new mapping exception type ('InvalidTypeIdException') for subtype resolution errors
-
#1028: Ignore
USE_BIG_DECIMAL_FOR_FLOATSforNaN/Infinity -
#1047: Allow use of
@JsonAnySetteron a Map-valued field, no need for setter -
#1082: Can not use static Creator factory methods for
Enums, withJsonCreator.Mode.PROPERTIES -
#1084: Change
TypeDeserializerBaseto takeJavaTypefordefaultImpl, notClass -
#1126: Allow deserialization of unknown Enums using a predefined value (annotated with
@JsonEnumDefaultValue) -
#1136: Implement
TokenBuffer.writeEmbeddedObject(Object) -
#1184: Allow overriding of
transientwith explicit inclusion with@JsonProperty -
#1207: Add new method(s) in
DeserializationProblemHandlerto allow handling of format mismatch problems -
#1221: Use
Throwable.addSuppressed()directly and/or via try-with-resources -
#1232: Add support for
JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES -
#1233: Add support for
JsonFormat.Feature.WRITE_SORTED_MAP_ENTRIES