Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

General data-binding package for Jackson (2.x): works on streaming API (core) implementation(s)

License

NotificationsYou must be signed in to change notification settings

FasterXML/jackson-databind

Repository files navigation

This project contains the general-purpose data-binding functionalityand tree-model forJackson Data Processor.It builds onStreaming API (stream parser/generator) package,and usesJackson Annotations for configuration.Project is licensed underApache License 2.0.

While the original use case for Jackson was JSON data-binding, it can now be used to read contentencoded in other data formats as well, as long as parser and generator implementations exist.Naming of classes uses word 'JSON' in many places even though there is no actual hard dependency to JSON format.

Status

TypeStatus
Build (CI)Build (github)
ArtifactMaven Central
OSS SponsorshipTidelift
JavadocsJavadoc
Code coverage (3.0)codecov.io
OpenSSF ScoreOpenSSF  Scorecard

Get it!

Maven

Functionality of this package is contained in Java packagetools.jackson.databind (for Jackson 3.x), and can be used using following Maven dependency:

<properties>  ...<!-- Use the latest version whenever possible.-->  <jackson.version>3.0.0</jackson.version>  ...</properties><dependencies>  ...  <dependency>    <groupId>tools.jackson.core</groupId>    <artifactId>jackson-databind</artifactId>    <version>${jackson.version}</version>  </dependency>  ...</dependencies>

Package also depends onjackson-core andjackson-annotations packages, but when using build toolslike Maven or Gradle, dependencies are automatically included.You may, however, want to usejackson-bom to ensure compatible versionsof dependencies.If not using build tool that can handle dependencies using project'spom.xml, you will need to downloadand include these 2 jars explicitly.

Non-Maven dependency resolution

For use cases that do not automatically resolve dependencies from Maven repositories, you can stilldownload jars fromCentral Maven repository.

Databind jar is also a functional OSGi bundle, with proper import/export declarations, so it can be use on OSGi container as is.

Jackson 2.10 and above includemodule-info.class definitions so the jar is also a proper Java Module (JPMS).

Jackson 2.12 and above include additional Gradle 6 Module Metadata for version alignment with Gradle.


Compatibility

JDK

Jackson-databind package baseline JDK requirements are as follows:

  • Versions 2.x require JDK 8
  • Versions 3.x require JDK 17

Android

List is incomplete due to compatibility checker addition being done for Jackson 2.13.

  • 2.14 - 2.19: Android SDK 26+
  • 3.0: Android SDK 34+

for information on Android SDK versions to Android Release names see [https://en.wikipedia.org/wiki/Android_version_history]


Use It!

More comprehensive documentation can be found fromJackson-docs repository; as well as fromWiki of this project.But here are brief introductionary tutorials, in recommended order of reading.

1 minute tutorial: POJOs to JSON and back

The most common usage is to take piece of JSON, and construct a Plain Old Java Object ("POJO") out of it. So let's start there. With simple 2-property POJO like this:

// Note: can use getters/setters as well; here we just use public fields directly:publicclassMyValue {publicStringname;publicintage;// NOTE: if using getters/setters, can keep fields `protected` or `private`}

we will need atools.jackson.databind.ObjectMapper instance, used for all data-binding, so let's construct one:

// With default settings can useObjectMappermapper =newObjectMapper();// create once, reuse// But if configuration needed, use builder pattern:ObjectMappermapper =JsonMapper.builder()// configuration    .build();

The default instance is fine for our use -- we will learn later on how to configure mapper instance if necessary. Usage is simple:

MyValuevalue =mapper.readValue(newFile("data.json"),MyValue.class);// or:value =mapper.readValue(newURL("http://some.com/api/entry.json"),MyValue.class);// or:value =mapper.readValue("{\"name\":\"Bob\",\"age\":13}",MyValue.class);

And if we want to write JSON, we do the reverse:

mapper.writeValue(newFile("result.json"),myResultObject);// or:byte[]jsonBytes =mapper.writeValueAsBytes(myResultObject);// or:StringjsonString =mapper.writeValueAsString(myResultObject);

So far so good?

3 minute tutorial: Generic collections, Tree Model

Beyond dealing with simple Bean-style POJOs, you can also handle JDKLists,Maps:

Map<String,Integer>scoreByName =mapper.readValue(jsonSource,Map.class);List<String>names =mapper.readValue(jsonSource,List.class);// and can obviously write out as wellmapper.writeValue(newFile("names.json"),names);

as long as JSON structure matches, and types are simple.If you have POJO values, you need to indicate actual type (note: this is NOT needed for POJO properties withList etc types):

Map<String,ResultValue>results =mapper.readValue(jsonSource,newTypeReference<Map<String,ResultValue>>() { } );// why extra work? Java Type Erasure will prevent type detection otherwise

(note: no extra effort needed for serialization, regardless of generic types)

But wait! There is more!

(enters Tree Model...)

Tree Model

While dealing withMaps,Lists and other "simple" Object types (Strings, Numbers, Booleans) can be simple, Object traversal can be cumbersome.This is where Jackson'sTree model can come in handy:

// can be read as generic JsonNode, if it can be Object or Array; or,// if known to be Object, as ObjectNode, if array, ArrayNode etc:JsonNoderoot =mapper.readTree("{\"name\":\"Joe\",\"age\": 13 }");Stringname =root.get("name").asText();intage =root.get("age").asInt();// can modify as well: this adds child Object as property 'other', set property 'type'root.withObject("/other").put("type","student");Stringjson =mapper.writeValueAsString(root);// prints below/*with above, we end up with something like as 'json' String:{  "name" : "Bob",  "age" : 13,  "other" : {    "type" : "student"  }}*/

Tree Model can be more convenient than data-binding, especially in cases where structure is highly dynamic, or does not map nicely to Java classes.

Finally, feel free to mix and match, and even in the same json document (useful when only part of the document is known and modeled in your code)

// Some parts of this json are modeled in our code, some are notJsonNoderoot =mapper.readTree(complexJson);Personp =mapper.treeToValue(root.get("person"),Person.class);// known single pojoMap<String,Object>dynamicmetadata =mapper.treeToValue(root.get("dynamicmetadata"),Map.class);// unknown smallish subfield, convert all to collectionsintsingledeep =root.get("deep").get("large").get("hiearchy").get("important").intValue();// single value in very deep optional subfield, ignoring the restintsingledeeppath =root.at("/deep/large/hiearchy/important").intValue();// json pathintsingledeeppathunique =root.findValue("important").intValue();// by unique field name// Send an aggregate json from heterogenous sourcesObjectNoderoot =mapper.createObjectNode();root.putPOJO("person",newPerson("Joe"));// simple pojoroot.putPOJO("friends",List.of(newPerson("Jane"),newPerson("Jack")));// genericsMap<String,Object>dynamicmetadata =Map.of("Some","Metadata");root.putPOJO("dynamicmetadata",dynamicmetadata);// collectionsroot.putPOJO("dynamicmetadata",mapper.valueToTree(dynamicmetadata));// same thingroot.set("dynamicmetadata",mapper.valueToTree(dynamicmetadata));// same thingroot.withObject("deep").withObject("large").withObject("hiearchy").put("important",42);// create as you goroot.withObject("/deep/large/hiearchy").put("important",42);// json pathmapper.writeValueAsString(root);

Supported for Jackson 2.16+ versions

// genericsList<Person>friends =mapper.treeToValue(root.get("friends"),newTypeReference<List<Person>>() { });// create as you go but without trying json pathroot.withObjectProperty("deep").withObjectProperty("large").withObjectProperty("hiearchy").put("important",42);

5 minute tutorial: Streaming parser, generator

As convenient as data-binding (to/from POJOs) can be; and as flexible as Tree model can be, there is one more canonical processing model available: incremental (aka "streaming") model.It is the underlying processing model that data-binding and Tree Model both build upon, but it is also exposed to users who want ultimate performance and/or control over parsing or generation details.

For in-depth explanation, look atJackson Core component.But let's look at a simple teaser to whet your appetite.

ObjectMappermapper = ...;// First: write simple JSON outputFilejsonFile =newFile("test.json");// note: method added in Jackson 2.11 (earlier would need to use// mapper.getFactory().createGenerator(...)JsonGeneratorg =mapper.createGenerator(jsonFile,JsonEncoding.UTF8);// write JSON: { "message" : "Hello world!" }g.writeStartObject();g.writeStringField("message","Hello world!");g.writeEndObject();g.close();// Second: read file backtry (JsonParserp =mapper.createParser(jsonFile)) {JsonTokent =p.nextToken();// Should be JsonToken.START_OBJECTt =p.nextToken();// JsonToken.FIELD_NAMEif ((t !=JsonToken.FIELD_NAME) || !"message".equals(p.getCurrentName())) {// handle error  }t =p.nextToken();if (t !=JsonToken.VALUE_STRING) {// similarly  }Stringmsg =p.getText();System.out.printf("My message to you is: %s!\n",msg);}

10 minute tutorial: configuration

There are two entry-level configuration mechanisms you are likely to use:Features andAnnotations.

Commonly used Features

Here are examples of configuration features that you are most likely to need to know about.

Let's start with higher-level data-binding configuration.With Jackson 3.x, you need to use "Builder"-style construction (2.x also supported direct configuration but this was removed to makeObjectMapper instances immutable and fully thread-safe)

// SerializationFeature for changing how JSON is written// to enable standard indentation ("pretty-printing"):ObjcetMappermapper =JsonMapper.builder()    .enable(SerializationFeature.INDENT_OUTPUT)// to allow serialization of "empty" POJOs (no properties to serialize)// (without this setting, an exception is thrown in those cases)    .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)// to write java.util.Date, Calendar as number (timestamp):    .disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS)// DeserializationFeature for changing how JSON is read as POJOs:// to prevent exception when encountering unknown property:    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)// to allow coercion of JSON empty String ("") to null Object value:    .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)    .build();

In addition, you may need to change some of low-level JSON parsing, generation details.This happens by enabling disabling:

  • StreamReadFeature /StreamWriteFeature for generic (format-agnostic) settings
  • JsonReadFeature /JsonWriteFeature for JSON-specific settings
ObjcetMappermapper =JsonMapper.builder()// StreamReadFeatures for configuring parsing settings:// to allow C/C++ style comments in JSON (non-standard, disabled by default)    .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS,true)// to allow (non-standard) unquoted field names in JSON:    .configure(JsonReadFeature.ALLOW_UNQUOTED_PROPERTY_NAMES,true)// to allow use of apostrophes (single quotes), non standard    .configure(JsonReadFeature.ALLOW_SINGLE_QUOTES,true)// JsonWriteFeature for configuring low-level JSON generation:// to force escaping of non-ASCII characters:    .configure(JsonWriteFeature.ESCAPE_NON_ASCII,true)        .build();

Full set of features are explained onJackson Features page.

Annotations: changing property names

The simplest annotation-based approach is to use@JsonProperty annotation like so:

publicclassMyBean {privateString_name;// without annotation, we'd get "theName", but we want "name":@JsonProperty("name")publicStringgetTheName() {return_name; }// note: it is enough to add annotation on just getter OR setter;// so we can omit it herepublicvoidsetTheName(Stringn) {_name =n; }}

There are other mechanisms to use for systematic naming changes, including use of "Naming Strategy" (via@JsonNaming annotation).

You can useMix-in Annotations to associate any and all Jackson-provided annotations.

Annotations: Ignoring properties

There are two main annotations that can be used to ignore properties:@JsonIgnore for individual properties; and@JsonIgnoreProperties for per-class definition

// means that if we see "foo" or "bar" in JSON, they will be quietly skipped// regardless of whether POJO has such properties@JsonIgnoreProperties({"foo","bar" })publicclassMyBean{// will not be written as JSON; nor assigned from JSON:@JsonIgnorepublicStringinternal;// no annotation, public field is read/written normallypublicStringexternal;@JsonIgnorepublicvoidsetCode(intc) {_code =c; }// note: will also be ignored because setter has annotation!publicintgetCode() {return_code; }}

As with renaming, note that annotations are "shared" between matching fields, getters and setters: if only one has@JsonIgnore, it affects others.But it is also possible to use "split" annotations, to for example:

publicclassReadButDontWriteProps {privateString_name;@JsonPropertypublicvoidsetName(Stringn) {_name =n; }@JsonIgnorepublicStringgetName() {return_name; }}

in this case, no "name" property would be written out (since 'getter' is ignored); but if "name" property was found from JSON, it would be assigned to POJO property!

For a more complete explanation of all possible ways of ignoring properties when writing out JSON, check"Filtering properties" article.

Annotations: using custom constructor

Unlike many other data-binding packages, Jackson does not require you to define "default constructor" (constructor that does not take arguments).While it will use one if nothing else is available, you can easily define that an argument-taking constructor is used:

publicclassCtorBean{publicfinalStringname;publicfinalintage;@JsonCreator// constructor can be public, private, whateverprivateCtorBean(@JsonProperty("name")Stringname,@JsonProperty("age")intage)  {this.name =name;this.age =age;  }}

Constructors are especially useful in supporting use ofImmutable objects.

Alternatively, you can also define "factory methods":

publicclassFactoryBean{// fields etc omitted for brevity@JsonCreatorpublicstaticFactoryBeancreate(@JsonProperty("name")Stringname) {// construct and return an instance    }}

Note that use of a "creator method" (@JsonCreator with@JsonProperty annotated arguments) does not preclude use of setters: youcan mix and match properties from constructor/factory method with ones thatare set via setters or directly using fields.

Tutorial: fancier stuff, conversions

One useful (but not very widely known) feature of Jackson is its abilityto do arbitrary POJO-to-POJO conversions. Conceptually you can think of conversions as sequence of 2 steps: first, writing a POJO as JSON, and second, binding that JSON into another kind of POJO. Implementation just skips actual generation of JSON, and uses more efficient intermediate representation.

Conversions work between any compatible types, and invocation is as simple as:

ResultTyperesult =mapper.convertValue(sourceObject,ResultType.class);

and as long as source and result types are compatible -- that is, if to-JSON, from-JSON sequence would succeed -- things will "just work".But here are a couple of potentially useful use cases:

// Convert from List<Integer> to int[]List<Integer>sourceList = ...;int[]ints =mapper.convertValue(sourceList,int[].class);// Convert a POJO into Map!Map<String,Object>propertyMap =mapper.convertValue(pojoValue,Map.class);// ... and backPojoTypepojo =mapper.convertValue(propertyMap,PojoType.class);// decode Base64! (default byte[] representation is base64-encoded String)Stringbase64 ="TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz";byte[]binary =mapper.convertValue(base64,byte[].class);

Basically, Jackson can work as a replacement for many Apache Commons components, for tasks like base64 encoding/decoding, and handling of "dyna beans" (Maps to/from POJOs).

Tutorial: Builder design pattern + Jackson

The Builder design pattern is a creational design pattern and can be used to create complex objects step by step.If we have an object that needs multiple checks on other dependencies, In such cases, it is preferred to use builder design pattern.

Let's consider the person structure, which has some optional fields

publicclassPerson {privatefinalStringname;privatefinalIntegerage;// getters}

Let’s see how we can employ its power in deserialization. First of all, let’s declare a private all-arguments constructor, and a Builder class.

privatePerson(Stringname,Integerage) {this.name =name;this.age =age;}staticclassBuilder {Stringname;Integerage;BuilderwithName(Stringname) {this.name =name;returnthis;    }BuilderwithAge(Integerage) {this.age =age;returnthis;    }publicPersonbuild() {returnnewPerson(name,age);    } }

First of all, we need to mark our class with@JsonDeserialize annotation, passing a builder parameter with a fully qualified domain name of a builder class.After that, we need to annotate the builder class itself as@JsonPOJOBuilder.

@JsonDeserialize(builder =Person.Builder.class)publicclassPerson {//...@JsonPOJOBuilderstaticclassBuilder {//...    }}

A simple unit test will be:

Stringjson ="{\"name\":\"Hassan\",\"age\":23}";Personperson =newObjectMapper().readValue(json,Person.class);assertEquals("Hassan",person.getName());assertEquals(23,person.getAge().intValue());

If your builder pattern implementation uses other prefixes for methods or uses other names than build() for the builder method Jackson also provide a handy way for you.

For example, if you have a builder class that uses the "set" prefix for its methods and use the create() method instead of build() for building the whole class, you have to annotate your class like:

@JsonPOJOBuilder(buildMethodName ="create",withPrefix ="set")staticclassBuilder {Stringname;Integerage;BuildersetName(Stringname) {this.name =name;returnthis;    }BuildersetAge(Integerage) {this.age =age;returnthis;    }publicPersoncreate() {returnnewPerson(name,age);    } }

To deserialize JSON fields under a different name than their object counterparts,the @JsonProperty annotation can be used within the builder on the appropriate fields.

@JsonPOJOBuilder(buildMethodName ="create",withPrefix ="set")staticclassBuilder {@JsonProperty("known_as")Stringname;Integerage;//...}

This will deserialize the JSON propertyknown_as into the builder fieldname. If a mapping like this is not provided (and further annotations aren't supplied to handle this), anUnrecognized field "known_as" exception will be thrown during deserialization if the field is provided anyways.

If you wish to refer to properties with more than one alias for deserialization, the@JsonAlias annotation can be used.

@JsonPOJOBuilder(buildMethodName ="create",withPrefix ="set")staticclassBuilder {@JsonProperty("known_as")@JsonAlias({"identifier","first_name"})Stringname;Integerage;//...}

This will deserialize JSON fields withknown_as, as well asidentifer andfirst_name intoname. Rather than an array of entries, a single alias can be used by specifying a string as suchJsonAlias("identifier").
Note: to use the@JsonAlias annotation, a@JsonProperty annotation must also be used.

Overall, Jackson library is very powerful in deserializing objects using builder pattern.

Tutorial: Collecting multiple errors (3.1+)

One recently introduced feature is the ability to collect multiple deserialization errors instead of failing fast on the first one. This can be really handy for validation use cases.

By default, if Jackson encounters a problem during deserialization -- say, string"xyz" for anint property -- it will immediately throw an exception and stop. But sometimes you want to see ALL the problems in one go.

Consider a case where you have a couple of fields with bad data:

classOrder {publicintorderId;publicDateorderDate;publicdoubleamount;}Stringjson ="{\"orderId\":\"not-a-number\",\"orderDate\":\"bad-date\",\"amount\":\"xyz\"}";

Normally you'd get an error aboutorderId, fix it, resubmit, then get error aboutorderDate, and so on. Not fun. So let's collect them all:

ObjectMappermapper =newJsonMapper();ObjectReaderreader =mapper.readerFor(Order.class).problemCollectingReader();try {Orderresult =reader.readValueCollectingProblems(json);// worked fine}catch (DeferredBindingExceptionex) {System.out.println("Found " +ex.getProblems().size() +" problems:");for (CollectedProblemproblem :ex.getProblems()) {System.out.println(problem.getPath() +": " +problem.getMessage());// Can also access problem.getRawValue() to see what the bad input was    }}

This will report all 3 problems at once. Much better.

By default, Jackson will collect up to 100 problems before giving up (to prevent DoS-style attacks with huge bad payloads). You can configure this:

ObjectReaderreader =mapper.readerFor(Order.class).problemCollectingReader(10);// limit to 10

Few things to keep in mind:

  1. This is best-effort: not all problems can be collected. Malformed JSON (like missing closing brace) or other structural problems will still fail immediately. But type conversion errors, unknown properties (if you enable that check), and such will be collected.
  2. Error paths use JSON Pointer notation (RFC 6901): so"/items/0/price" means first item initems array,price field. Special characters get escaped (~ becomes~0,/ becomes~1).
  3. Each call toreadValueCollectingProblems() gets its own problem bucket, so it's thread-safe to reuse the sameObjectReader.
  4. Fields that fail to deserialize get default values (0 for primitives, null for objects) during the attempt, but if any problems are collected, only the problems are reported in theDeferredBindingException - the partial result is not returned.

This is particularly useful for things like REST API validation (return all validation errors to client), or batch processing (log errors but keep going), or development tooling.

Contribute!

We would love to get your contribution, whether it's in form of bug reports, Requests for Enhancement (RFE), documentation, or code patches.

SeeCONTRIBUTING for details on things like:

  • Community, ways to interact (mailing lists, gitter)
  • Issue tracking (GitHub Issues)
  • Paperwork: CLA (just once before the first merged contribution)

Limitation on Dependencies by Core Components

One additional limitation exists for so-called core components (streaming api, jackson-annotations and jackson-databind): no additional dependencies are allowed beyond:

  • Core components may rely on any methods included in the supported JDK
    • Minimum Java version is Java 7 for Jackson 2.7 - 2.12 ofjackson-databind and most non-core components
    • Minimum Java version is Java 8 for Jackson 2.13 and later
  • Jackson-databind (this package) depends on the other two (annotations, streaming).

This means that anything that has to rely on additional APIs or libraries needs to be built as an extension,usually a Jackson module.

Branches

3.x branch is for developing the next major Jackson version -- 3.0 -- but thereare active maintenance branches in which much of development happens:

  • 2.x is the branch for "next" minor version to release (2.20 as of May 2025)
  • 2.19 is the current stable minor 2.x version
  • 2.18 is for selected backported fixes

Older branches are usually not maintained after being declared as closedonJackson Releases page,but exist just in case a rare emergency patch is needed.All released versions have matching git tags (e.g.jackson-dataformats-binary-2.12.3).


Differences from Jackson 1.x

Repository contains versions 2.0 and above: source code for last (1.x) release, 1.9, is available atJackson-1 repo.

Main differences compared to 1.x "mapper" jar are:

  • Maven build instead of Ant
  • Java package:
    • 1.x:org.codehaus.jackson.mapper
    • 2.x:com.fasterxml.jackson.databind
    • 3.x:tools.jackson.databind

Support

Community support

Jackson components are supported by the Jackson community through mailing lists, Gitter forum, Github issues. SeeParticipation, Contributing for full details.

Enterprise support

Available as part of theTidelift Subscription.

The maintainers ofjackson-databind and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.Learn more.


Further reading

Related:

About

General data-binding package for Jackson (2.x): works on streaming API (core) implementation(s)

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors314

Languages


[8]ページ先頭

©2009-2025 Movatter.jp