Which annotation to use for unknown JSON object properties deserialized into unknown Java subtypes #276
-
Hello, I am designing an extensible format (JSON or Yaml). For instance, let's say I have this JSON document: {
"known_1": "a value", // known in advance
"known_2": "another value", // known in advance
"extra_1": { // not known in advance
"yet": "another value"
},
"extra_2": "and another one" // not known in advance
} And these base classes: import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.function.Function;
import java.util.stream.Collectors;
class Document {
@JsonCreator
public Document(@JsonProperty("known_1") String knownValue1,
@JsonProperty("known_2") String knownValue2,
/* ??? */ Extras extraValues) { // <---------------- which annotation can work here??
// [...]
}
// [...]
}
// this is registered as follows:
// var module = new SimpleModule();
// module.addDeserializer(Extras.class, new ExtrasDeserializer());
// return YAMLMapper.builder()
// .addModule(module)
// .build();
class ExtrasDeserializer extends StdDeserializer<Extras> {
private final List<ExtraProvider<? extends Extra>> providers;
ExtrasDeserializer() {
super(Extras.class);
providers = ServiceLoader.load(ExtraProvider.class)
.stream()
.map(provider -> (ExtraProvider<? extends Extra>) provider.get())
.collect(Collectors.toList());
}
@Override
public Extras deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectNode object = jsonParser.getCodec().readTree(jsonParser);
return new Extras(providers.stream()
.map(provider -> (Extra) provider.apply(object.deepCopy()))
.filter(Objects::nonNull)
.toList());
}
}
class Extras {
private final List<Extra> extras;
public Extras(List<Extra> extras) {
this.extras = extras;
}
public List<Extra> getExtras() {
return extras;
}
}
interface Extra {
}
interface ExtraProvider<T extends Extra> extends Function<ObjectNode, T> {
} Users provide their own Is there a way to deserialize all these unknown properties into unknown The whole setup demo'ed here can change, the only requirement is that the extra keys (here |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Annotation that might work would be
|
Beta Was this translation helpful? Give feedback.
Annotation that might work would be
@JsonAnySetter
forMap
orObjectNode
like so (fromAnySetterForCreator562Test.java
):