FasterXML / FasterXML/jackson-dataformats-binary
`jackson-dataformat-ion` type serialization behavior
- Dominant language
- Java
- Stars
- 347
- Forks
- 156
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 22
Description
# jackson-dataformat-ion polymorphic behaviors
## [SSCCE](http://sscce.org/) to demonstrate behaviors.
This sample code depends on `jackson-dataformat-ion`, `jackson-annotations`, `jackson-databind`, and `jackson-core`.
```java
import com.amazon.ion.IonValue;// for jackson-dataformat-ion 2.10+
// import software.amazon.ion.IonValue; // for jackson-dataformat-ion 2.8-2.9
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.dataformat.ion.IonObjectMapper;
import java.io.IOException;
import java.awt.Point;
public class Main {
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
static public class BaseClass extends Point {
public BaseClass(int x, int y) { super(x, y); }
}
public static class Subclass extends BaseClass {
public Subclass(int x, int y) { super(x, y); }
}
public static void main(String... a) throws IOException {
IonObjectMapper mapper = new IonObjectMapper();
Subclass subclass = new Subclass(10, 42);
Point unrelated = new Point(10, 42);
// By default no type annotation => no type information
IonValue unrelatedAsIon = mapper.writeValueAsIonValue(unrelated);
report(unrelatedAsIon);
// Form of serialized information will depend on jackson-dataformat-ion version
IonValue subclassAsIon = mapper.writeValueAsIonValue(subclass);
report(subclassAsIon);
// This will fail for jackson-dataformat-ion >= 2.9
BaseClass roundTripInstance = mapper.readValue(subclassAsIon, BaseClass.class);
assert (roundTripInstance instanceof Subclass);
assert (subclass.equals(roundTripInstance));
}
private static void report(IonValue v) {
System.out.printf("%s%n", v.toPrettyString());
}
}
```
## Available jackson-dataformat-ion behaviors:
### v2.8
* Honors `@JsonTypeInfo` annotations, no type information without explicit guidance.
We need to modify the example to work with 2.8:
```diff
- import com.amazon.ion.IonValue;// for jackson-dataformat-ion 2.10+
+ // import com.amazon.ion.IonValue;// for jackson-dataformat-ion 2.10+
- // import software.amazon.ion.IonValue; // for jackson-dataformat-ion 2.8-2.9
+ import software.amazon.ion.IonValue; // for jackson-dataformat-ion 2.8-2.9
```
Afterwards it should yield:
#### Output
```plain
{
x:10e0,
y:42e0
}
{
'@class':"Main$Subclass"
x:10e0,
y:42e0
}
```
### v2.9 - Present (2.12 release)
* Use exclusively Ion annotations to convey type information, ignore `As.PROPERTY` from `@JsonTypeInfo` annotation. `@JsonTypeInfo` still needed to cause typed serialization.
Assuming 2.10+ for consistent `IonValue` import statement.
#### Output
```plain
{
x:10e0,
y:42e0
}
Main$Subclass::{
x:10e0,
y:42e0
}
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class Main$BaseClass]: missing type id property '@class'
at [Source: UNKNOWN; line: -1, column: -1]
at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:1790)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1319)
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:303)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:166)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:107)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithType(BeanDeserializerBase.java:1197)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
at com.fasterxml.jackson.dataformat.ion.IonObjectMapper.readValue(IonObjectMapper.java:154)
at Main.main(Main.java:33)
```
### After [PR #232](https://github.com/FasterXML/jackson-dataformats-binary/pull/232)
#### Output
```plain
{
x:10e0,
y:42e0
}
Main$Subclass::{
x:10e0,
y:42e0
}
```
### After [PR #232](https://github.com/FasterXML/jackson-dataformats-binary/pull/232), with native types disabled at Mapper construction
```diff
- IonObjectMapper m = new IonObjectMapper();
+ IonObjectMapper m = new IonObjectMapper()
+ .disable(IonGenerator.Feature.USE_NATIVE_TYPE_ID);
```
#### Output
```plain
{
x:10e0,
y:42e0
}
{
'@class':"Main$Subclass"
x:10e0,
y:42e0
}
```
## Open Question: What is the ideal behavior?
After [PR #232](https://github.com/FasterXML/jackson-dataformats-binary/pull/232) both achievable `IonMapper` configurations won't serialize type data without e.g. a POJO annotation, but write behavior can seem a little surprising. A user who has attempted to configure property-based serialization of type information will be surprised to see it showing up as an annotation instead.
An argument can be made that the most locally or specifically expressed user preference should control behavior, in which case a `@JsonTypeInfo` annotation should override format-native behavior. I.e. the serialization of `Subclass` above should naturally be:
```plain
{
'@class':"Main$Subclass"
x:10e0,
y:42e0
}
```
This is complicated by the fact that `As.Property` is the default for `@JsonTypeInfo`. Take this example:
```java
@JsonTypeInfo(use=Id.Class)
public class BaseClass {}
```
The user has not specified `include` or `as` and it's not obvious that the user does not want format-native type serialization behavior.
This behavior doesn't emerge from `jackson-dataformat-ion` directly, but from JsonGenerator in `jackson-core`, AsPropertyTypeSerializer in `jackson-databind`, etc.
I'm looking for some commentary on intent here, and what options might be available. It's not clear to me how much flexibility there is here.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.