├── .devcontainer
├── Dockerfile
└── devcontainer.json
├── .editorconfig
├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ └── build.yml
├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── io
│ │ └── vavr
│ │ └── jackson
│ │ └── datatype
│ │ ├── VavrModule.java
│ │ ├── VavrTypeModifier.java
│ │ ├── deserialize
│ │ ├── ArrayDeserializer.java
│ │ ├── CharSeqDeserializer.java
│ │ ├── EitherDeserializer.java
│ │ ├── LazyDeserializer.java
│ │ ├── MapDeserializer.java
│ │ ├── MaplikeDeserializer.java
│ │ ├── MultimapDeserializer.java
│ │ ├── OptionDeserializer.java
│ │ ├── PriorityQueueDeserializer.java
│ │ ├── SeqDeserializer.java
│ │ ├── SerializableDeserializer.java
│ │ ├── SetDeserializer.java
│ │ ├── Tuple0Deserializer.java
│ │ ├── Tuple1Deserializer.java
│ │ ├── Tuple2Deserializer.java
│ │ ├── Tuple3Deserializer.java
│ │ ├── Tuple4Deserializer.java
│ │ ├── Tuple5Deserializer.java
│ │ ├── Tuple6Deserializer.java
│ │ ├── Tuple7Deserializer.java
│ │ ├── Tuple8Deserializer.java
│ │ ├── TupleDeserializer.java
│ │ ├── ValueDeserializer.java
│ │ └── VavrDeserializers.java
│ │ └── serialize
│ │ ├── ArraySerializer.java
│ │ ├── CharSeqSerializer.java
│ │ ├── EitherSerializer.java
│ │ ├── HListSerializer.java
│ │ ├── LazySerializer.java
│ │ ├── MapSerializer.java
│ │ ├── MultimapSerializer.java
│ │ ├── OptionSerializer.java
│ │ ├── SerializableSerializer.java
│ │ ├── Tuple0Serializer.java
│ │ ├── Tuple1Serializer.java
│ │ ├── Tuple2Serializer.java
│ │ ├── Tuple3Serializer.java
│ │ ├── Tuple4Serializer.java
│ │ ├── Tuple5Serializer.java
│ │ ├── Tuple6Serializer.java
│ │ ├── Tuple7Serializer.java
│ │ ├── Tuple8Serializer.java
│ │ ├── TupleSerializer.java
│ │ ├── UnwrappingOptionSerializer.java
│ │ ├── ValueSerializer.java
│ │ └── VavrSerializers.java
└── resources
│ └── META-INF
│ └── services
│ └── com.fasterxml.jackson.databind.Module
└── test
└── java
├── generator
├── BindingClass.java
├── ExtFieldsPojo.java
├── Generator.java
├── ParameterizedPojo.java
├── PolymorphicPojo.java
├── SimplePojo.java
└── utils
│ ├── Initializer.java
│ ├── PoetHelpers.java
│ └── Serializer.java
└── io
└── vavr
└── jackson
├── datatype
├── BaseTest.java
├── CharSeqTest.java
├── EitherTest.java
├── FunctionTest.java
├── LazyTest.java
├── MixedTest.java
├── OptionJsonMergeTest.java
├── OptionPlainTest.java
├── OptionTest.java
├── PriorityQueueTest.java
├── ScalarTest.java
├── SerializationFeatureTest.java
├── ServiceLoaderTest.java
├── bean
│ ├── AbstractContentTest.java
│ ├── BeanAnnotationTest.java
│ ├── BeanTest.java
│ ├── ComplexBeanTest.java
│ └── ComplexClass.java
├── docs
│ └── ReadmeTest.java
├── map
│ ├── HashMapJsonMergeTest.java
│ ├── HashMapTest.java
│ ├── LinkedHashMapJsonMergeTest.java
│ ├── LinkedHashMapTest.java
│ ├── MapJsonMergeTest.java
│ ├── MapTest.java
│ ├── TreeMapJsonMergeTest.java
│ └── TreeMapTest.java
├── multimap
│ ├── HashMultimapTest.java
│ ├── LinkedHashMultimapTest.java
│ ├── MultimapTest.java
│ └── TreeMultimapTest.java
├── seq
│ ├── ArrayJsonMergeTest.java
│ ├── ArrayTest.java
│ ├── IndexedSeqJsonMergeTest.java
│ ├── IndexedSeqTest.java
│ ├── ListJsonMergeTest.java
│ ├── ListTest.java
│ ├── QueueJsonMergeTest.java
│ ├── QueueTest.java
│ ├── SeqJsonMergeTest.java
│ ├── SeqTest.java
│ ├── StreamJsonMergeTest.java
│ ├── StreamTest.java
│ ├── VectorJsonMergeTest.java
│ └── VectorTest.java
├── set
│ ├── HashSetJsonMergeTest.java
│ ├── HashSetTest.java
│ ├── LinkedHashSetJsonMergeTest.java
│ ├── LinkedHashSetTest.java
│ ├── SetJsonMergeTest.java
│ ├── SetTest.java
│ ├── TreeSetJsonMergeTest.java
│ └── TreeSetTest.java
└── tuples
│ ├── Tuple1Test.java
│ ├── Tuple2Test.java
│ ├── Tuple3Test.java
│ ├── Tuple4Test.java
│ ├── Tuple5Test.java
│ ├── Tuple6Test.java
│ ├── Tuple7Test.java
│ ├── Tuple8Test.java
│ ├── TupleTest.java
│ └── TupleXTest.java
├── generated
├── BindingClassTest.java
├── ExtFieldsPojoTest.java
├── ParameterizedPojoTest.java
├── PolymorphicPojoTest.java
└── SimplePojoTest.java
└── issues
├── Issue141Test.java
├── Issue142Test.java
├── Issue149Test.java
└── Issue154Test.java
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG VARIANT=17
2 | FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT}
3 |
4 | ARG NODE_VERSION="none"
5 | RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
6 |
7 | ARG USER=vscode
8 | VOLUME /home/$USER/.m2
9 | VOLUME /home/$USER/.gradle
10 |
11 | ARG JAVA_VERSION=23.0.2-tem
12 | RUN sudo mkdir /home/$USER/.m2 /home/$USER/.gradle && sudo chown $USER:$USER /home/$USER/.m2 /home/$USER/.gradle
13 | RUN bash -lc '. /usr/local/sdkman/bin/sdkman-init.sh && sdk install java $JAVA_VERSION && sdk use java $JAVA_VERSION'
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/java
3 | {
4 | "name": "Java",
5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6 | //https://mcr.microsoft.com/v2/vscode/devcontainers/java/tags/list
7 | //"image": "mcr.microsoft.com/devcontainers/java:21",
8 | "dockerFile": "Dockerfile",
9 | "build": {
10 | "args": {
11 | "NODE_VERSION": "22.11.0"
12 | }
13 | },
14 | "hostRequirements": {
15 | "cpus": 2
16 | },
17 | "features": {
18 | "ghcr.io/devcontainers/features/java:1": {
19 | "version": "none",
20 | "installMaven": "true",
21 | "installGradle": "true"
22 | },
23 | "ghcr.io/devcontainers/features/sshd:1": {
24 | "version": "latest"
25 | },
26 | "ghcr.io/devcontainers/features/docker-in-docker:2": {
27 | "version": "latest",
28 | "dockerDashComposeVersion": "v2"
29 | }
30 | },
31 | "customizations": {
32 | "vscode": {
33 | "extensions": [
34 | "vscjava.vscode-java-pack",
35 | "vscjava.vscode-java-debug",
36 | "vscjava.vscode-maven",
37 | "vscjava.vscode-gradle",
38 | "vscjava.vscode-java-dependency",
39 | "vscjava.vscode-java-test",
40 | "vscjava.vscode-spring-boot-dashboard",
41 | "vscjava.vscode-spring-initializr",
42 | "redhat.java",
43 | "vmware.vscode-boot-dev-pack",
44 | "vmware.vscode-spring-boot",
45 | "ms-azuretools.vscode-docker",
46 | "redhat.vscode-xml",
47 | "redhat.vscode-yaml",
48 | "editorconfig.editorconfig",
49 | "github.copilot",
50 | "github.copilot-chat"
51 | ]
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.java]
2 | indent_size = 4
3 | indent_style = space
4 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @pivovarit
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "maven"
4 | target-branch: "main"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 | time: "02:00"
9 | - package-ecosystem: "github-actions"
10 | directory: "/"
11 | target-branch: "main"
12 | schedule:
13 | interval: "daily"
14 | time: "02:00"
15 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build and test
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 | merge_group:
11 |
12 | jobs:
13 | build:
14 | name: "Compile against JDKs and OSes"
15 | strategy:
16 | matrix:
17 | os: [ubuntu-latest, macos-latest]
18 | java: [8, 11, 17, 21, 24]
19 | exclude:
20 | - java: 8
21 | os: macos-latest
22 | fail-fast: false
23 | runs-on: ${{ matrix.os }}
24 | steps:
25 | - uses: actions/checkout@v4
26 | - uses: actions/setup-java@v4
27 | with:
28 | distribution: temurin
29 | java-version: ${{ matrix.java }}
30 | cache: maven
31 |
32 | - name: Build with Maven
33 | run: mvn --batch-mode clean verify
34 |
35 | test:
36 | name: "Test"
37 | needs: [build]
38 | runs-on: ubuntu-latest
39 | strategy:
40 | matrix:
41 | java: [8, 11, 17, 21, 24]
42 | fasterxmlVersion: [2.18.3, 2.19.0]
43 | fail-fast: false
44 |
45 | steps:
46 | - uses: actions/checkout@v4
47 | - uses: actions/setup-java@v4
48 | with:
49 | java-version: ${{ matrix.java }}
50 | distribution: temurin
51 | cache: maven
52 |
53 | - name: Run tests with specific Jackson version
54 | run: mvn --batch-mode clean verify -DfasterxmlVersion=${{ matrix.fasterxmlVersion }}
55 |
56 | results:
57 | if: ${{ always() }}
58 | runs-on: ubuntu-latest
59 | name: Verification Results
60 | needs: [test]
61 | steps:
62 | - name: Check test job status
63 | run: |
64 | if [[ "${{ needs.test.result }}" == "success" || "${{ needs.test.result }}" == "skipped" ]]; then
65 | exit 0
66 | else
67 | exit 1
68 | fi
69 |
70 | deploy-snapshot:
71 | runs-on: ubuntu-latest
72 | needs: results
73 | if: github.ref == 'refs/heads/main'
74 |
75 | steps:
76 | - uses: actions/checkout@v4
77 | - name: Setup JDK
78 | uses: actions/setup-java@v4
79 | with:
80 | distribution: 'temurin'
81 | java-version: '21'
82 | cache: 'maven'
83 | server-id: central
84 | server-username: CENTRAL_USERNAME
85 | server-password: CENTRAL_PASSWORD
86 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
87 |
88 | - name: Deploy Snapshot
89 | run: mvn -B --no-transfer-progress -Pmaven-central-release -DskipTests=true deploy
90 | env:
91 | CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
92 | CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
93 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
94 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | out
3 | .gradle
4 | .idea
5 | *.iml
6 | *.ipr
7 | *.iws
8 |
9 | target
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vavr-jackson
2 |
3 | [](https://github.com/vavr-io/vavr-jackson/actions/workflows/build.yml)
4 | 
5 | [](https://codecov.io/github/vavr-io/vavr-jackson?branch=master)
6 |
7 | Jackson datatype module for [Vavr](https://vavr.io/) library
8 |
9 | [](https://starchart.cc/vavr-io/vavr-jackson)
10 |
11 | ## Usage
12 |
13 | ### Maven
14 |
15 | ```xml
16 |
17 | io.vavr
18 | vavr-jackson
19 | 0.10.3
20 |
21 | ```
22 |
23 | ### Gradle
24 |
25 | ```groovy
26 | compile("io.vavr:vavr-jackson:0.10.3")
27 | ```
28 |
29 | ### Registering module
30 | Just register a new instance of VavrModule
31 | ```java
32 | ObjectMapper mapper = new ObjectMapper();
33 | mapper.registerModule(new VavrModule());
34 | ```
35 |
36 | ### Serialization/deserialization
37 |
38 |
39 |
40 | ```java
41 | String json = mapper.writeValueAsString(List.of(1));
42 | // = [1]
43 | List restored = mapper.readValue(json, new TypeReference>() {});
44 | // = List(1)
45 | ```
46 |
47 | ## Using Developer Versions
48 |
49 | Developer versions can be found [here](https://oss.sonatype.org/content/repositories/snapshots/io/vavr/vavr-jackson).
50 |
51 | ### Maven
52 |
53 | ```xml
54 |
55 | io.vavr
56 | vavr-jackson
57 | 0.10.6-SNAPSHOT
58 |
59 | ```
60 |
61 | Ensure that your `~/.m2/settings.xml` contains the following:
62 |
63 | ```xml
64 |
65 |
66 | allow-snapshots
67 |
68 | true
69 |
70 |
71 |
72 | snapshots-repo
73 | https://oss.sonatype.org/content/repositories/snapshots
74 |
75 | false
76 |
77 |
78 | true
79 |
80 |
81 |
82 |
83 |
84 | ```
85 |
86 | ### Gradle
87 |
88 | ```groovy
89 | compile("io.vavr:vavr-jackson:0.10.6-SNAPSHOT")
90 | ```
91 |
92 | Ensure that your `build.gradle` contains the following:
93 |
94 | ```groovy
95 | repositories {
96 | mavenCentral()
97 | maven {
98 | url "https://oss.sonatype.org/content/repositories/snapshots"
99 | }
100 | }
101 | ```
102 |
--------------------------------------------------------------------------------
/src/main/java/io/vavr/jackson/datatype/VavrModule.java:
--------------------------------------------------------------------------------
1 | /* __ __ __ __ __ ___
2 | * \ \ / / \ \ / / __/
3 | * \ \/ / /\ \ \/ / /
4 | * \____/__/ \__\____/__/
5 | *
6 | * Copyright 2014-2025 Vavr, http://vavr.io
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package io.vavr.jackson.datatype;
21 |
22 | import com.fasterxml.jackson.databind.module.SimpleModule;
23 | import io.vavr.jackson.datatype.deserialize.VavrDeserializers;
24 | import io.vavr.jackson.datatype.serialize.VavrSerializers;
25 |
26 | public class VavrModule extends SimpleModule {
27 |
28 | private static final long serialVersionUID = 1L;
29 |
30 | public static class Settings {
31 |
32 | private boolean plainOption = true;
33 | private boolean deserializeNullAsEmptyCollection = false;
34 |
35 | public Settings useOptionInPlainFormat(boolean value) {
36 | plainOption = value;
37 | return this;
38 | }
39 |
40 | public Settings deserializeNullAsEmptyCollection(boolean value) {
41 | deserializeNullAsEmptyCollection = value;
42 | return this;
43 | }
44 |
45 | public boolean useOptionInPlainFormat() {
46 | return plainOption;
47 | }
48 |
49 | public boolean deserializeNullAsEmptyCollection() {
50 | return deserializeNullAsEmptyCollection;
51 | }
52 | }
53 |
54 | private final Settings settings;
55 |
56 | public VavrModule() {
57 | this(new Settings());
58 | }
59 |
60 | public VavrModule(Settings settings) {
61 | this.settings = settings;
62 | }
63 |
64 | @Override
65 | public void setupModule(SetupContext context) {
66 | super.setupModule(context);
67 | context.addSerializers(new VavrSerializers(settings));
68 | context.addDeserializers(new VavrDeserializers(settings));
69 | context.addTypeModifier(new VavrTypeModifier());
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/io/vavr/jackson/datatype/VavrTypeModifier.java:
--------------------------------------------------------------------------------
1 | /* __ __ __ __ __ ___
2 | * \ \ / / \ \ / / __/
3 | * \ \/ / /\ \ \/ / /
4 | * \____/__/ \__\____/__/
5 | *
6 | * Copyright 2014-2025 Vavr, http://vavr.io
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package io.vavr.jackson.datatype;
21 |
22 | import com.fasterxml.jackson.databind.JavaType;
23 | import com.fasterxml.jackson.databind.type.CollectionLikeType;
24 | import com.fasterxml.jackson.databind.type.MapLikeType;
25 | import com.fasterxml.jackson.databind.type.ReferenceType;
26 | import com.fasterxml.jackson.databind.type.TypeBindings;
27 | import com.fasterxml.jackson.databind.type.TypeFactory;
28 | import com.fasterxml.jackson.databind.type.TypeModifier;
29 | import io.vavr.Lazy;
30 | import io.vavr.collection.CharSeq;
31 | import io.vavr.collection.Map;
32 | import io.vavr.collection.Multimap;
33 | import io.vavr.collection.PriorityQueue;
34 | import io.vavr.collection.Seq;
35 | import io.vavr.collection.Set;
36 | import io.vavr.control.Option;
37 |
38 | import java.lang.reflect.Type;
39 |
40 | public class VavrTypeModifier extends TypeModifier {
41 |
42 | @Override
43 | public JavaType modifyType(JavaType type, Type jdkType, TypeBindings bindings, TypeFactory typeFactory) {
44 | final Class> raw = type.getRawClass();
45 | if (Seq.class.isAssignableFrom(raw) && CharSeq.class != raw) {
46 | return CollectionLikeType.upgradeFrom(type, type.containedTypeOrUnknown(0));
47 | }
48 | if (Set.class.isAssignableFrom(raw)) {
49 | return CollectionLikeType.upgradeFrom(type, type.containedTypeOrUnknown(0));
50 | }
51 | if (PriorityQueue.class.isAssignableFrom(raw)) {
52 | return CollectionLikeType.upgradeFrom(type, type.containedTypeOrUnknown(0));
53 | }
54 | if (Map.class.isAssignableFrom(raw)) {
55 | return MapLikeType.upgradeFrom(type, type.containedTypeOrUnknown(0), type.containedTypeOrUnknown(1));
56 | }
57 | if (Multimap.class.isAssignableFrom(raw)) {
58 | return MapLikeType.upgradeFrom(type, type.containedTypeOrUnknown(0), type.containedTypeOrUnknown(1));
59 | }
60 | if (Lazy.class.isAssignableFrom(raw)) {
61 | return ReferenceType.upgradeFrom(type, type.containedTypeOrUnknown(0));
62 | }
63 | if (Option.class.isAssignableFrom(raw)) {
64 | return ReferenceType.upgradeFrom(type, type.containedTypeOrUnknown(0));
65 | }
66 | return type;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/io/vavr/jackson/datatype/deserialize/CharSeqDeserializer.java:
--------------------------------------------------------------------------------
1 | /* __ __ __ __ __ ___
2 | * \ \ / / \ \ / / __/
3 | * \ \/ / /\ \ \/ / /
4 | * \____/__/ \__\____/__/
5 | *
6 | * Copyright 2014-2025 Vavr, http://vavr.io
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package io.vavr.jackson.datatype.deserialize;
21 |
22 | import com.fasterxml.jackson.core.JsonParser;
23 | import com.fasterxml.jackson.core.JsonToken;
24 | import com.fasterxml.jackson.databind.DeserializationContext;
25 | import com.fasterxml.jackson.databind.JavaType;
26 | import com.fasterxml.jackson.databind.JsonDeserializer;
27 | import com.fasterxml.jackson.databind.JsonMappingException;
28 | import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
29 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
30 | import com.fasterxml.jackson.databind.type.TypeFactory;
31 | import io.vavr.collection.CharSeq;
32 |
33 | import java.io.IOException;
34 |
35 | class CharSeqDeserializer extends StdDeserializer implements ResolvableDeserializer {
36 |
37 | private static final long serialVersionUID = 1L;
38 |
39 | private JsonDeserializer> deserializer;
40 |
41 | CharSeqDeserializer(JavaType valueType) {
42 | super(valueType);
43 | }
44 |
45 | @Override
46 | public CharSeq deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
47 | Object obj = deserializer.deserialize(p, ctxt);
48 | if (obj instanceof String) {
49 | return CharSeq.of((String) obj);
50 | } else {
51 | throw JsonMappingException.from(p, String.format("Unexpected token (%s), expected %s: CharSeq can only be deserialized from String", p.getCurrentToken(), JsonToken.VALUE_STRING));
52 | }
53 | }
54 |
55 | @Override
56 | public void resolve(DeserializationContext ctxt) throws JsonMappingException {
57 | deserializer = ctxt.findContextualValueDeserializer(TypeFactory.unknownType(), null);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/io/vavr/jackson/datatype/deserialize/LazyDeserializer.java:
--------------------------------------------------------------------------------
1 | /* __ __ __ __ __ ___
2 | * \ \ / / \ \ / / __/
3 | * \ \/ / /\ \ \/ / /
4 | * \____/__/ \__\____/__/
5 | *
6 | * Copyright 2014-2025 Vavr, http://vavr.io
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package io.vavr.jackson.datatype.deserialize;
21 |
22 | import com.fasterxml.jackson.core.JsonParser;
23 | import com.fasterxml.jackson.databind.BeanProperty;
24 | import com.fasterxml.jackson.databind.DeserializationContext;
25 | import com.fasterxml.jackson.databind.JavaType;
26 | import com.fasterxml.jackson.databind.JsonDeserializer;
27 | import com.fasterxml.jackson.databind.JsonMappingException;
28 | import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
29 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
30 | import io.vavr.Lazy;
31 |
32 | import java.io.IOException;
33 |
34 | class LazyDeserializer extends ValueDeserializer> implements ContextualDeserializer {
35 |
36 | private static final long serialVersionUID = 1L;
37 |
38 | private final JavaType fullType;
39 | private final JavaType valueType;
40 | private final TypeDeserializer valueTypeDeserializer;
41 | private final JsonDeserializer> valueDeserializer;
42 |
43 | LazyDeserializer(JavaType fullType, JavaType valueType, TypeDeserializer typeDeser, JsonDeserializer> valueDeser) {
44 | super(valueType, 1);
45 | this.fullType = fullType;
46 | this.valueType = valueType;
47 | this.valueTypeDeserializer = typeDeser;
48 | this.valueDeserializer = valueDeser;
49 | }
50 |
51 | private LazyDeserializer(LazyDeserializer origin, TypeDeserializer typeDeser, JsonDeserializer> valueDeser) {
52 | this(origin.fullType, origin.valueType, typeDeser, valueDeser);
53 | }
54 |
55 | @Override
56 | public Lazy> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
57 | Object value;
58 | if (valueTypeDeserializer == null) {
59 | value = valueDeserializer.deserialize(p, ctxt);
60 | } else {
61 | value = valueDeserializer.deserializeWithType(p, ctxt, valueTypeDeserializer);
62 | }
63 | return Lazy.of(() -> value);
64 | }
65 |
66 | @Override
67 | public Lazy> getNullValue(DeserializationContext ctxt) {
68 | return Lazy.of(() -> null);
69 | }
70 |
71 | @Override
72 | public JsonDeserializer> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
73 | JsonDeserializer> deser = valueDeserializer;
74 | TypeDeserializer typeDeser = valueTypeDeserializer;
75 | JavaType refType = valueType;
76 |
77 | if (deser == null) {
78 | deser = ctxt.findContextualValueDeserializer(refType, property);
79 | } else { // otherwise directly assigned, probably not contextual yet:
80 | deser = ctxt.handleSecondaryContextualization(deser, property, refType);
81 | }
82 | if (typeDeser != null) {
83 | typeDeser = typeDeser.forProperty(property);
84 | }
85 | return new LazyDeserializer(this, typeDeser, deser);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/io/vavr/jackson/datatype/deserialize/MaplikeDeserializer.java:
--------------------------------------------------------------------------------
1 | /* __ __ __ __ __ ___
2 | * \ \ / / \ \ / / __/
3 | * \ \/ / /\ \ \/ / /
4 | * \____/__/ \__\____/__/
5 | *
6 | * Copyright 2014-2025 Vavr, http://vavr.io
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | package io.vavr.jackson.datatype.deserialize;
21 |
22 | import com.fasterxml.jackson.databind.BeanProperty;
23 | import com.fasterxml.jackson.databind.DeserializationContext;
24 | import com.fasterxml.jackson.databind.JavaType;
25 | import com.fasterxml.jackson.databind.JsonDeserializer;
26 | import com.fasterxml.jackson.databind.JsonMappingException;
27 | import com.fasterxml.jackson.databind.KeyDeserializer;
28 | import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
29 | import com.fasterxml.jackson.databind.deser.ContextualKeyDeserializer;
30 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
31 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
32 | import com.fasterxml.jackson.databind.type.MapLikeType;
33 |
34 | import java.io.Serializable;
35 | import java.util.Comparator;
36 |
37 | abstract class MaplikeDeserializer extends StdDeserializer implements ContextualDeserializer {
38 |
39 | private static final long serialVersionUID = 1L;
40 |
41 | final MapLikeType mapType;
42 |
43 | final Comparator