Since, com.fasterxml.jackson.annotation.JsonFormat
is an annotation you can implement your own com.fasterxml.jackson.databind.AnnotationIntrospector
and return value you want for all your enums. Simple example you can find below:
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(new DynamicEnumAnnotationIntrospector(), new JacksonAnnotationIntrospector()));
System.out.println(mapper.writeValueAsString(Thing.THING_A));
}
}
class DynamicEnumAnnotationIntrospector extends AnnotationIntrospector {
@Override
public Version version() {
return new Version(1, 0, 0, "Dynamic enum object", "your.package", "jackson.dynamic.enum");
}
@Override
public JsonFormat.Value findFormat(Annotated memberOrClass) {
final Class<?> rawType = memberOrClass.getRawType();
if (rawType.isEnum() && rawType.getPackage().getName().startsWith("your.package")) {
return JsonFormat.Value.forShape(JsonFormat.Shape.OBJECT);
}
return super.findFormat(memberOrClass);
}
}
Above code prints:
{"thing":"a"}
Now, you can create two instances of ObjectMapper
and for one configure your own annotation introspector and second one leave with default. If you really want to use it in dynamic way you can create one ObjectMapper
for each available Shape
value and select required one for a given shape:
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Objects;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
JsonFactory factory = new JsonFactory();
for (Shape shape : Shape.values()) {
ObjectMapper mapper = factory.getWithEnumShapeSetTo(shape);
System.out.println(shape + " => " + mapper.writeValueAsString(Thing.THING_A));
}
}
}
class JsonFactory {
private final AnnotationIntrospector defaultIntrospector = new JacksonAnnotationIntrospector();
private final EnumMap<Shape, ObjectMapper> instances = new EnumMap<>(Shape.class);
public JsonFactory() {
final List<Shape> notAllowed = Arrays.asList(Shape.BOOLEAN, Shape.BINARY);
Arrays.stream(Shape.values())
.filter(shape -> !notAllowed.contains(shape))
.forEach(shape -> instances.put(shape, createNewWithEnumShape(shape)));
}
private ObjectMapper createNewWithEnumShape(Shape shape) {
DynamicEnumAnnotationIntrospector enumIntrospector = new DynamicEnumAnnotationIntrospector(shape);
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(enumIntrospector, defaultIntrospector));
return mapper;
}
public ObjectMapper getWithEnumShapeSetTo(Shape shape) {
Objects.requireNonNull(shape);
final ObjectMapper mapper = instances.get(shape);
if (mapper == null) {
return new ObjectMapper();
}
return mapper;
}
}
class DynamicEnumAnnotationIntrospector extends AnnotationIntrospector {
private final Shape shape;
public DynamicEnumAnnotationIntrospector(Shape shape) {
this.shape = Objects.requireNonNull(shape);
}
@Override
public Version version() {
return new Version(1, 0, 0, "Dynamic enum shape", "your.package", "jackson.dynamic.enum");
}
@Override
public JsonFormat.Value findFormat(Annotated memberOrClass) {
final Class<?> rawType = memberOrClass.getRawType();
if (rawType.isEnum() && rawType.getPackage().getName().startsWith("your.package")) {
return JsonFormat.Value.forShape(shape);
}
return super.findFormat(memberOrClass);
}
}
Above code prints:
ANY => "THING_A"
NATURAL => "THING_A"
SCALAR => "THING_A"
ARRAY => 0
OBJECT => {"thing":"a"}
NUMBER => 0
NUMBER_FLOAT => 0
NUMBER_INT => 0
STRING => "THING_A"
BOOLEAN => "THING_A"
BINARY => "THING_A"
Above code of course is overkill but I wanted to show possibilities we have. We have only 3 different outputs so you can group values with the same output and create maximum 3 different ObjectMappers
.