Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/infobip/infobip-jackson-extension
Library which provides new features for (de)serialization on top of Jackson library.
https://github.com/infobip/infobip-jackson-extension
jackson-databind jackson-library serialization
Last synced: 4 days ago
JSON representation
Library which provides new features for (de)serialization on top of Jackson library.
- Host: GitHub
- URL: https://github.com/infobip/infobip-jackson-extension
- Owner: infobip
- License: apache-2.0
- Created: 2020-08-13T07:35:32.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-06-26T10:10:46.000Z (5 months ago)
- Last Synced: 2024-06-27T11:23:25.970Z (5 months ago)
- Topics: jackson-databind, jackson-library, serialization
- Language: Java
- Homepage:
- Size: 158 KB
- Stars: 5
- Watchers: 9
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Infobip Jackson Extension
![](https://github.com/infobip/infobip-jackson-extension/workflows/maven/badge.svg)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.infobip/infobip-jackson-extension-spring-boot-starter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.infobip/infobip-jackson-extension-spring-boot-starter)
[![Coverage Status](https://coveralls.io/repos/github/infobip/infobip-jackson-extension/badge.svg?branch=master)](https://coveralls.io/github/infobip/infobip-jackson-extension?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/github/infobip/infobip-jackson-extension/badge.svg)](https://snyk.io/test/github/infobip/infobip-jackson-extension)Library which provides new features for (de)serialization on top of [Jackson library](https://github.com/FasterXML/jackson).
## Contents
1. [Changelog](#Changelog)
1. [Setup](#Setup)
1. [Features](#Features)
* [Simple json hierarchy](#SimpleJsonHierarchy)
* [Overriding type json property name](#OverridingTypeJsonPropertyName)
* [Lower case type value](#LowerCaseTypeValue)
* [Multi level hierarchies](#MultiLevelHierarchies)
* [Hierarchy per property approach](#HierarchyPerPropertyApproach)
* [Single property approach](#SinglePropertyApproach)
* [Parallel hierarchies](#ParallelHierarchies)
* [Typeless (present property)](#Typeless)
* [Dynamic hierarchy](#DynamicHierarchy)
* [Single Argument Property Creator annotationless support](#SingleArgumentPropertyCreatorAnnotationlessSupport)For changes check the [changelog](CHANGELOG.md).
All examples have corresponding tests and additional usage examples can be found in tests.
In examples, tests and [Single Argument Property Creator annotationless support](#SingleArgumentPropertyCreatorAnnotationlessSupport) it's required that
the code is compiled with `-parameters` compiler option and that `jackson-module-parameter-names` module is used.Parameter names module:
```xmlcom.fasterxml.jackson.module
jackson-module-parameter-names```
Compiler plugin setup:
```xmlorg.apache.maven.plugins
maven-compiler-plugin
${maven-compiler-plugin.version}
...
-parameters
-parameters
...
```
Parameter names module makes parameter names visible to the Jackson meaning it can map json properties to constructor parameter names so there's no redundant
Jackson annotation to redeclare them. There's an important catch here: JSON field name, Java accessors and constructor parameter name all must match!### Spring Boot
Just include the following dependency:
```xml
com.infobip
infobip-jackson-extension-spring-boot-starter
${infobip-jackson-extension.version}```
### Without Spring Boot
Include the following dependency:
```xml
com.infobip
infobip-jackson-extension-module
${infobip-jackson-extension.version}```
Register the module with `ObjectMapper`:
```java
objectMapper.registerModule(new InfobipJacksonModule());
```For models that have a type represented by an enum you can use simple typed json approach:
```java
interface FooBar extends SimpleJsonHierarchy {
}record Foo(String foo) implements FooBar {
@Override
public FooBarType getType() {
return FooBarType.FOO;
}}
record Bar(String bar) implements FooBar {
@Override
public FooBarType getType() {
return FooBarType.BAR;
}}
@Getter
@AllArgsConstructor
enum FooBarType implements TypeProvider {
FOO(Foo.class),
BAR(Bar.class);private final Class extends FooBar> type;
}
```[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/SimpleJsonHierarchyDeserializerTest.java)
#### Overriding type json property nameName of the property can be overridden:
[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/CustomTypeFieldSimpleJsonHierarchyTest.java)
Casing of the property type value can be overridden:
[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/LowerCaseTypeSimpleJsonHierarchyTest.java)
Multi level hierarchies are supported with 2 different approach.
The first approach is used when there is a property per hierarchy.
The second approach is used when only one property is shared, but property values are globally unique, meaning
there can't be two hierarchies that have the same property value.
If values were not unique, it would be unclear to which class to deserialize.Note that these examples have simplified sub hierarchies for brevity of the documentation, but you can use different
mechanisms previously defined for specific sub hierarchy - e.g. one hierarchy can use the default type property
but another one can [override type json property name](#OverridingTypeJsonPropertyName).
When there is a property per hierarchy following can be used:```java
@JsonTypeResolveWith(AnimalJsonTypeResolver.class)
interface Animal {
AnimalType getAnimalType();
}static class AnimalJsonTypeResolver extends SimpleJsonTypeResolver {
public AnimalJsonTypeResolver() {
super(AnimalType.class, "animalType");
}
}@JsonTypeResolveWith(MammalJsonTypeResolver.class)
interface Mammal extends Animal {
MammalType getMammalType();
}static class MammalJsonTypeResolver extends SimpleJsonTypeResolver {
public MammalJsonTypeResolver() {
super(MammalType.class, "mammalType");
}
}record Human(String name) implements Mammal {
@Override
public AnimalType getAnimalType() {
return AnimalType.MAMMAL;
}@Override
public MammalType getMammalType() {
return MammalType.HUMAN;
}}
@Getter
@AllArgsConstructor
enum AnimalType implements TypeProvider {
MAMMAL(Mammal.class);private final Class extends Animal> type;
}@Getter
@AllArgsConstructor
enum MammalType implements TypeProvider {
HUMAN(Human.class);private final Class extends Mammal> type;
}
```[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/MultiHierarchyJsonTypedDeserializerTest.java)
When there is a single property shared for all hierarchies following can be used:```java
sealed interface Animal extends SealedSimpleJsonHierarchies {}
sealed interface Bird extends Animal, SimpleJsonHierarchy {
}
@Getter
@AllArgsConstructor
enum BirdType implements TypeProvider {
PARROT(Parrot.class);private final Class extends Bird> type;
}record Parrot() implements Bird {
@Override
public BirdType getType() {
return BirdType.PARROT;
}
}sealed interface Mammal extends Animal, SimpleJsonHierarchy {
}
@Getter
@AllArgsConstructor
enum MammalType implements TypeProvider {
HUMAN(Human.class);private final Class extends Mammal> type;
}record Human(String name) implements Mammal {
@Override
public MammalType getType() {
return MammalType.HUMAN;
}
}
```[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/SealedSimpleJsonHierarchiesTest.java)
In case you have multiple hierarchies that reuse the same enum TypeProvider can present an issue, use this approach to as a guide to possible solution:
[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/ParallelHierarchyJsonTypedDeserializerTest.java).
### Typeless (present property)In case you don't want to (or can't - third party API) include type information in json, you can use this approach:
```java
interface Bike extends PresentPropertyJsonHierarchy {
}record RoadBike(String roadBike) implements Bike {
}record Bmx(String bmx) implements Bike {
}@Getter
@AllArgsConstructor
enum BikeType implements TypeProvider {
ROAD_BIKE(RoadBike.class),
BMX(Bmx.class);private final Class extends Bike> type;
}
```[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/PresentPropertyDeserializerTest.java).
Notice that by default snake cased type names are translated to camel case properties (e.g. `ROAD_BIKE` -> `roadBike`).
If you want to use different casing you can provide your own resolver by extending `PresentPropertyJsonTypeResolver`:
```java
static class LowerUnderscorePresentPropertyJsonTypeResolver & TypeProvider> extends PresentPropertyJsonTypeResolver {public LowerUnderscorePresentPropertyJsonTypeResolver(Class type) {
super(type, CaseFormat.LOWER_UNDERSCORE);
}
}
```
Then your model may look as follows:
```java
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonTypeResolveWith(LowerUnderscorePresentPropertyJsonTypeResolver.class)
interface Bike extends PresentPropertyJsonHierarchy {}
static class LowerUnderscorePresentPropertyJsonTypeResolver & TypeProvider>
extends PresentPropertyJsonTypeResolver {public LowerUnderscorePresentPropertyJsonTypeResolver(Class type) {
super(type, CaseFormat.LOWER_UNDERSCORE);
}
}record RoadBike(String roadBike) implements Bike {
}
record MountainBike(String mountainBike) implements Bike {
}
```
Notice standard jackson `@JsonNaming` annotation in `Bike` interface.[Showcase](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/PresentPropertyCaseFormatDeserializerTest.java).
In case root of the hierarchy is decoupled from the leaves in different compilation units.
Also it can be seen as annotationless alternative.[Showcase without type provider](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/dynamic/DynamicHierarchyDeserializerTest.java).
[Showcase with type provider](infobip-jackson-extension-module/src/test/java/com/infobip/jackson/dynamic/DynamicHierarchyDeserializerWithTypeProviderTest.java).
In case Spring Boot starter is used you only need to register DynamicHierarchyDeserializer as a @Bean, starter handles wiring with Jackson.
### Single Argument Property Creator annotationless supportThis module also adds support for deserializing single property value objects when using parameter names module:
```java
class Foo {
private final Bar bar;Foo(Bar bar) {
this.bar = bar;
}
}
```without any additional configuration or annotations.
Related issues: https://github.com/FasterXML/jackson-databind/issues/1498, https://github.com/spring-projects/spring-boot/issues/26023.- Java 17
If you have an idea for a new feature or want to report a bug please use the issue tracker.
Pull requests are welcome!
This library is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).