I have a number of Immutables classes, like:
@Value.Immutable
interface Foo {
String bar();
}
To make these compatible with Jackson, I need to label these with @JsonDeserialize
and @JsonSerialize
, per the Immutables manual:
@Value.Immutable
@JsonDeserialize(as = ImmutableFoo.class)
@JsonSerialize(as = ImmutableFoo.class)
interface Foo {
String bar();
}
This is a bit cumbersome at development time and noisy in the code. I'd like to configure Jackson such that any time it encounters a class annotated with @Value.Immutable
that the serializer it chooses is ImmutableX
for class name X
and similarly for deserialization.
How do I go about configuring Jackson to do this?
I have a number of Immutables classes, like:
@Value.Immutable
interface Foo {
String bar();
}
To make these compatible with Jackson, I need to label these with @JsonDeserialize
and @JsonSerialize
, per the Immutables manual:
@Value.Immutable
@JsonDeserialize(as = ImmutableFoo.class)
@JsonSerialize(as = ImmutableFoo.class)
interface Foo {
String bar();
}
This is a bit cumbersome at development time and noisy in the code. I'd like to configure Jackson such that any time it encounters a class annotated with @Value.Immutable
that the serializer it chooses is ImmutableX
for class name X
and similarly for deserialization.
How do I go about configuring Jackson to do this?
Share Improve this question asked Mar 26 at 2:33 Mark ElliotMark Elliot 77.1k23 gold badges144 silver badges162 bronze badges 3 |1 Answer
Reset to default 0You can do as this section says - add @JsonSerialize
to a your own @Value.Style
annotation.
@Target({ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize
@Value.Style(/* add more styling here if you need... */)
@interface JacksonImmutable {}
// package-info.java:
@JacksonImmutable
package com.example;
Then all the @Value.Immutable
interfaces can be serialised. This also works for deserialisation if you are always using the concrete ImmutableXXX
types, but if you want to work with the interfaces, it is a lot more difficult.
One way would be to find all the interface-implementation pairings using Reflections and add it to a custom SimpleModule
.
var mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("My Module", Version.unknownVersion());
var reflections = new Reflections(
new ConfigurationBuilder()
.forPackages("") // specify a package prefix here if you know where all your immutable classes are
.addScanners(Scanners.TypesAnnotated, Scanners.SubTypes)
);
for (var type : reflections.getTypesAnnotatedWith(Value.Immutable.class)) {
if (!type.isInterface()) { continue; }
if (!type.getPackage().isAnnotationPresent(JacksonImmutable.class)) { continue; }
helper(type, module, reflections);
}
mapper.registerModule(module);
// where the "helper" method (used for capturing the wildcards) is:
private static <T> void helper(Class<T> type, SimpleModule module, Reflections reflections) {
var implClass = reflections.getSubTypesOf(type).stream()
.filter(x -> x.getSimpleName().equals("Immutable" + type.getSimpleName())).findFirst();
implClass.ifPresent(aClass -> module.addAbstractTypeMapping(type, aClass));
}
Though I'm not sure if doing all this is worth it just to avoid a few lines of annotations.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744167566a4561377.html
@JsonImmutable
, but I don't think there's any way for Jackson to see the existingImmutable
annotation without resorting to hackery like replacing or shadowing the class to alter the retention policy. – shmosel Commented Mar 26 at 2:56