Class A looks like this:
#EqualsAndHashCode(callSuper = true)
#Data
#AllArgsConstructor
public final class A extends TreeSet<B> {
private final a;
private b;
private c;
public A(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
}
}
Class B:
#Data
#AllArgsConstructor
#EqualsAndHashCode
#ToString
public final class B {
private final int x;
private final double y;
}
When I serialize a class A object using Jackson:
jsonString = objectMapper.writeValueAsString(class_a_object);
I get a json Array like this:
[
{
"x": 3,
"y": 3.23
},
{
"x": 4,
"y": 2.12
},...
]
but the member variables a,b,c are missing. Is there a way I can include them into the json string?
Jackson recognises class A as a collection and register CollectionSerializer to serialise A's instances. We can modify default serialiser and provide custom serialiser. We can use BeanSerializerModifier to do that and reuse collection serialiser in custom implementation. To generate valid JSON you need to provide property name for set values.
Example:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.type.CollectionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.File;
import java.io.IOException;
import java.util.TreeSet;
public class ModifyCollectionSerializerApp {
public static void main(String[] args) throws IOException {
A a = new A(1, 2);
a.add(new B(22, 2.2));
a.add(new B(33, 3.3));
SimpleModule aModule = new SimpleModule();
aModule.setSerializerModifier(new ABeanSerializerModifier());
JsonMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(aModule)
.build();
String json = mapper.writeValueAsString(a);
System.out.println(json);
}
}
class ABeanSerializerModifier extends BeanSerializerModifier {
#Override
public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config, CollectionType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
return new AJsonSerializer(serializer);
}
}
class AJsonSerializer extends JsonSerializer<A> {
private final JsonSerializer valuesSerializer;
AJsonSerializer(JsonSerializer valuesSerializer) {
this.valuesSerializer = valuesSerializer;
}
#Override
public void serialize(A value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeNumberField("a", value.getA());
gen.writeNumberField("b", value.getB());
gen.writeFieldName("values");
valuesSerializer.serialize(value, gen, serializers);
gen.writeEndObject();
}
}
#EqualsAndHashCode(callSuper = true)
#Data
#AllArgsConstructor
class A extends TreeSet<B> {
private final int a;
private final int b;
}
#Data
#AllArgsConstructor
#EqualsAndHashCode
#ToString
class B implements Comparable<B> {
private final int x;
private final double y;
#Override
public int compareTo(B o) {
return this.x - o.x;
}
}
Above code prints:
{
"a" : 1,
"b" : 2,
"values" : [ {
"x" : 22,
"y" : 2.2
}, {
"x" : 33,
"y" : 3.3
} ]
}
Related
I'm creating a common class to standardize my JSON structure as written below,
public class Wrapper<T> {
private SoaHeader soaHeader;
private T payload;
}
public class PayloadFoo {
private String foo;
}
public class PayloadBar {
private String bar;
}
public class main(){
var foo = new Wrapper<PayloadFoo>();
var bar = new Wrapper<PayloadBar>();
}
Then later the expected JSON result for both foo and bar are
{
"foo": {
"soaHeader": {},
"payload": {
"foo": ""
}
}
}
and
{
"bar": {
"soaHeader": {},
"payload": {
"bar": ""
}
}
}
Can Jackson do such task by put either #JsonTypeName or #JsonRootName annotation on the PayloadFoo and PayloadBar classes? or any suggestion how can I achieve this? Thankyou
Jackson can handle this by using the #JsonTypeName annotation on the PayloadFoo and PayloadBar classes and the #JsonTypeInfo annotation on the Wrapper class.
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
public class JsonSubTypesExample {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
public static void main(String[] args) throws JsonProcessingException {
Wrapper<PayloadFoo> payloadFooWrapper = new Wrapper<>(new SoaHeader(), new PayloadFoo("foo"));
Wrapper<PayloadBar> payloadBarWrapper = new Wrapper<>(new SoaHeader(), new PayloadBar("bar"));
System.out.println(OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(payloadFooWrapper));
System.out.println(OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(payloadBarWrapper));
}
#JsonSubTypes({
#JsonSubTypes.Type(value = PayloadFoo.class, name = "foo"),
#JsonSubTypes.Type(value = PayloadBar.class, name = "bar"),
})
#Data
#ToString
#NoArgsConstructor
#AllArgsConstructor
public static class Wrapper<T> {
private SoaHeader soaHeader;
private T payload;
}
#JsonTypeName("foo")
#Data
#ToString
#NoArgsConstructor
#AllArgsConstructor
public static class PayloadFoo {
private String foo;
}
#JsonTypeName("bar")
#Data
#ToString
#NoArgsConstructor
#AllArgsConstructor
public static class PayloadBar {
private String bar;
}
#Data
#ToString
public static class SoaHeader {
}
}
I'm fetching addresses from an external API. This is the class representing the addresses:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Address implements Serializable {
private static final long serialVersionUID = -7134571546367230214L;
private String street;
private int houseNumber;
private String district;
private String city;
private String state;
private String zipCode;
}
However, when the given address doesn't have a houseNumber, the API will return a string such as "NO NUMBER" on the houseNumber field, causing Jackson to throw a deserialization error, since it was expecting an integer number and got a string.
How can I tell Jackson to convert houseNumber to 0 when it finds a string value?
You could try with a custom deserializer on the field:
#JsonDeserialize(using = HouseNoDeserializer.class)
private int houseNumber;
The deserializer could look like this:
class HouseNoDeserializer extends JsonDeserializer<Integer> {
#Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
//read the value as a string since you don't know whether it is a number or a string
String v = p.readValueAs(String.class);
try {
//try to parse the string to an integer, if not return 0 as required (it is a non-numeric string)
return Integer.parseInt(v);
} catch(NumberFormatException nfe) {
return 0;
}
}
}
However, I'd change houseNumber to take String anyways because right now you can't support numbers such as "1/c", "123a", etc. which are common at least in some countries.
You could then do without a custom deserializer and simply add some logic to the setter or apply it after parsing the json, i.e. replace "NO NUMBER" with another value as needed.
You can provide custom com.fasterxml.jackson.databind.deser.DeserializationProblemHandler and handle all these kind of business values generally for all POJO classes:
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.IOException;
public class HandleErrorsApp {
private final static JsonMapper JSON_MAPPER = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(new JavaTimeModule())
.addHandler(new ProjectDeserializationProblemHandler())
.build();
public static void main(String[] args) throws Exception {
var json = "{\"houseNumber\":\"NO_ADDRESS\"}";
var address = JSON_MAPPER.readValue(json, Address.class);
System.out.println(address);
}
}
class ProjectDeserializationProblemHandler extends DeserializationProblemHandler {
#Override
public Object handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg) throws IOException {
if (targetType == int.class && valueToConvert.equals("NO_ADDRESS")) {
return 0;
}
return super.handleWeirdStringValue(ctxt, targetType, valueToConvert, failureMsg);
}
}
#Data
#NoArgsConstructor
#AllArgsConstructor
class Address {
private int houseNumber;
}
Or you can provide custom com.fasterxml.jackson.databind.util.StdConverter implementation which has a little bit simpler interface than JsonDeserializer:
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.util.StdConverter;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.math.NumberUtils;
public class HandleErrorsApp {
private final static JsonMapper JSON_MAPPER = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(new JavaTimeModule())
.build();
public static void main(String[] args) throws Exception {
var json = "{\"houseNumber\":\"NO_ADDRESS\"}";
var address = JSON_MAPPER.readValue(json, Address.class);
System.out.println(address);
}
}
class StringIntConverter extends StdConverter<String, Integer> {
#Override
public Integer convert(String value) {
return NumberUtils.toInt(value, 0);
}
}
#Data
#NoArgsConstructor
#AllArgsConstructor
class Address {
#JsonDeserialize(converter = StringIntConverter.class)
private int houseNumber;
}
In both cases program prints:
Address(houseNumber=0)
I am using Jackson to serialize my Java POJO classes. In addition to fields, I have in Java POJO, I would like to add some additional information in JSON I am writing my own custom CustomClassSerializer. If I use this class and register to ObjectMapper then I get the error:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type org.acme.Tiger (by serializer of type org.acme.CustomModule$CustomClassSerializer)
I am unable to understand what might be going wrong here. If I remove the custom registered model then everything works perfectly.
Can someone please let me know what may be the cause of this issue? I am currently using Jackson 2.13.2 latest version dependencies: jackson-core, jackson-databind, jackson-annotations, jackson-datatype-jdk8:
Following is the sample code:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.*;
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "type")
#JsonSubTypes({#JsonSubTypes.Type(value = Bat.class, name = "Bat"),
#JsonSubTypes.Type(value = Tiger.class, name = "Tiger")})
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Animal {
private String type;
private String name;
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
#Data
#NoArgsConstructor
#AllArgsConstructor
#JsonTypeName("Tiger")
public class Tiger extends Animal {
private String livingType;
private String foundIn;
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
#Data
#NoArgsConstructor
#AllArgsConstructor
#JsonTypeName("Bat")
public class Bat extends Animal{
private String livingType;
private String foundIn;
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
import java.io.IOException;
public class CustomModule extends SimpleModule {
public CustomModule() {
addSerializer(Tiger.class, new CustomClassSerializer());
}
private static class CustomClassSerializer extends JsonSerializer {
#Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
jgen.writeObjectField("my_extra_field1", "some data");
jgen.writeObjectField("my_extra_field2", "some more data");
JavaType javaType = provider.constructType(Tiger.class);
BeanDescription beanDesc = provider.getConfig().introspect(javaType);
JsonSerializer<Object> serializer = BeanSerializerFactory.instance.createSerializer(provider, javaType);
serializer.unwrappingSerializer(null).serialize(value, jgen, provider);
jgen.writeEndObject();
}
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TestMain {
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.registerModule(new CustomModule());
Tiger tiger = new Tiger();
tiger.setType("Tiger");
tiger.setName("Shera");
tiger.setFoundIn("Ground");
tiger.setLivingType("Tree");
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(tiger));
}
}
I would like to know what are the causes for the above-mentioned exception.
I don't think I can write really efficient Jackson code while being a Gson-oriented guy, but I guess you could incorporate the following Q/As to resolve your question:
https://stackoverflow.com/a/27893673/12232870 - in order to overcome your issue;
https://stackoverflow.com/a/31057934/12232870 - in order to use the default serialization strategies.
Also, I'd like to refactor your code (a lot) in order to make it flexible by using the strategy design pattern (where necessary), and demonstrate how it works using with simple unit tests.
public final class InterceptingSerializerModifier<T>
extends BeanSerializerModifier {
public interface IAppender<T> {
void append(JsonGenerator generator, T value)
throws IOException;
}
private final Class<T> baseClass;
private final IAppender<? super T> appender;
private InterceptingSerializerModifier(final Class<T> baseClass, final IAppender<? super T> appender) {
this.baseClass = baseClass;
this.appender = appender;
}
public static <T> BeanSerializerModifier create(final Class<T> baseClass, final IAppender<? super T> appender) {
return new InterceptingSerializerModifier<>(baseClass, appender);
}
#Override
public JsonSerializer<?> modifySerializer(final SerializationConfig config, final BeanDescription description, final JsonSerializer<?> serializer) {
if ( !baseClass.isAssignableFrom(description.getBeanClass()) ) {
return serializer;
}
#SuppressWarnings("unchecked")
final JsonSerializer<? super T> castSerializer = (JsonSerializer<? super T>) serializer;
return InterceptingJsonSerializer.create(castSerializer, appender);
}
private static final class InterceptingJsonSerializer<T>
extends JsonSerializer<T> {
private static final NameTransformer identityNameTransformer = new NameTransformer() {
#Override
public String transform(final String name) {
return name;
}
#Override
public String reverse(final String transformed) {
return transformed;
}
};
private final JsonSerializer<? super T> unwrappedSerializer;
private final IAppender<? super T> appender;
private InterceptingJsonSerializer(final JsonSerializer<? super T> unwrappedSerializer, final IAppender<? super T> appender) {
this.unwrappedSerializer = unwrappedSerializer;
this.appender = appender;
}
private static <T> JsonSerializer<T> create(final JsonSerializer<? super T> serializer, final IAppender<? super T> appender) {
return new InterceptingJsonSerializer<>(serializer.unwrappingSerializer(identityNameTransformer), appender);
}
#Override
public void serializeWithType(final T value, final JsonGenerator generator, final SerializerProvider provider, final TypeSerializer serializer)
throws IOException {
serializer.writeTypePrefix(generator, serializer.typeId(value, JsonToken.START_OBJECT));
doSerialize(value, generator, provider);
serializer.writeTypeSuffix(generator, serializer.typeId(value, JsonToken.START_OBJECT));
}
#Override
public void serialize(final T value, final JsonGenerator generator, final SerializerProvider provider)
throws IOException {
generator.writeStartObject();
doSerialize(value, generator, provider);
generator.writeEndObject();
}
private void doSerialize(final T value, final JsonGenerator generator, final SerializerProvider provider)
throws IOException {
unwrappedSerializer.serialize(value, generator, provider);
appender.append(generator, value);
}
}
}
public final class InterceptingSerializerModifierTest {
private static final BeanSerializerModifier unit = InterceptingSerializerModifier.create(
IValue.class,
(generator, value) -> {
if ( value instanceof Foo foo ) {
generator.writeObjectField("#extra.message", "this is from foo: " + foo.value);
} else if ( value instanceof Bar bar ) {
generator.writeObjectField("#extra.message", "this is from bar: " + bar.value);
} else {
generator.writeObjectField("#extra.message", "something else...");
}
}
);
private static final ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new SimpleModule()
.setSerializerModifier(unit)
);
private static Stream<Arguments> test() {
return Stream.of(
Arguments.of(
"{\"#type\":\"FOO\",\"value\":1,\"#extra.message\":\"this is from foo: 1\"}",
new Foo(1)
),
Arguments.of(
"{\"#type\":\"BAR\",\"value\":2.0,\"#extra.message\":\"this is from bar: 2.0\"}",
new Bar(2)
)
);
}
#ParameterizedTest
#MethodSource
public void test(final String expectedJson, final IValue actualValue)
throws JsonProcessingException {
Assertions.assertEquals(expectedJson, objectMapper.writeValueAsString(actualValue));
}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
#JsonSubTypes({
#JsonSubTypes.Type(value = Foo.class, name = "FOO"),
#JsonSubTypes.Type(value = Bar.class, name = "BAR")
})
private sealed interface IValue
permits Foo, Bar {
}
#RequiredArgsConstructor(access = AccessLevel.PRIVATE)
private static final class Foo
implements IValue {
#Getter
private final int value;
}
#RequiredArgsConstructor(access = AccessLevel.PRIVATE)
private static final class Bar
implements IValue {
#Getter
private final double value;
}
}
I hope the code above is pretty self-explaining. You may also want to enhance the code in order to make identityNameTransformer injectable too, if you need to use extra property name transformations.
Unrelated to the subject, but duplicating JSON object property names like my_extra_field in your question may be considered not recommended (not sure if vulnerable). See more: Does JSON syntax allow duplicate keys in an object? .
Lets say we have simple json string json = {"key1":"value1", "key2":"value2"} and java class
class Foo {
private String field1;
private Integer field2;
//setter & getter
}
Moreover we don't want to change the Foo class. Note that json keys don't match with Foo's fields name.
Is there simple way we can deserilize json string to Foo class with Jackson or any other library?
You can use the following json libraries and build a custom deserializer as shown below.
jackson-annotations-2.10.4,
jackson-core-2.10.4,
jackson.databind-2.10.4
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.IntNode;
import java.io.IOException;
public class FooDeserializer extends StdDeserializer<Foo> {
public static void main (String [] args) throws JsonProcessingException {
String json = "{\"key1\":\"value1\", \"key2\":100}";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Foo.class, new FooDeserializer());
mapper.registerModule(module);
Foo foo = mapper.readValue(json, Foo.class);
System.out.println(foo);
}
public FooDeserializer() {
this(null);
}
public FooDeserializer(Class<?> vc) {
super(vc);
}
#Override
public Foo deserialize(JsonParser jp, DeserializationContext ctx)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String field1 = node.get("key1").asText();
int field2 = (Integer) ((IntNode) node.get("key2")).numberValue();
return new Foo(field1,field2);
}
}
I want to include only fields in my classes that have my custom annotation #MyInclude but Jackson ends up ignoring everything. What am I doing wrong?
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.setAnnotationIntrospector(new IgnoreIntrospector());
MyNestedObject nestedObject = new MyNestedObject("value1", "value2");
MyObject object = new MyObject();
object.setNestedObject(nestedObject);
String json = mapper.writeValueAsString(object); //This returns {}
}
public static class IgnoreIntrospector extends JacksonAnnotationIntrospector {
private static final long serialVersionUID = -3951086067314107368L;
#Override
public boolean hasIgnoreMarker(AnnotatedMember m) {
return !m.hasAnnotation(MyInclude.class) || super.hasIgnoreMarker(m);
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class MyObject {
#MyInclude
private MyNestedObject nestedObject;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class MyNestedObject {
#MyInclude
private String value1;
private String value2;
}
mapper.writeValueAsString(object) is returning {} but it should return NestedObject with value1 populated instead (ignoring value2).
If I update my IgnoreIntrospector.hasIgnoreMarker () to just super.hasIgnoreMarker(m) then everything would be included in the json string.
The IgnoreIntrospector alone wasn't enough. Since my custom annotations were only on fields, I needed to disable all visibility:
mapper.setAnnotationIntrospector(new IgnoreIntrospector());
mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
mapper.setVisibility(mapper.getDeserializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
And updated my IgnoreIntrospector:
public static class IgnoreIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(AnnotatedMember m) {
return m instanceof AnnotatedField && _findAnnotation(m, MyInclude.class) == null;
}
}
Alternatively, override both hasIgnoreMarker() and findNameForSerialization():
JsonMapper jsonMapper = JsonMapper.builder()
.annotationIntrospector(new JacksonAnnotationIntrospector()
{
#Override
public boolean hasIgnoreMarker(AnnotatedMember m)
{
return m.hasAnnotation(CustomIgnore.class) || super.hasIgnoreMarker(m);
}
#Override
public PropertyName findNameForSerialization(Annotated a)
{
if(a.hasAnnotation(CustomIgnore.class)) return null;
return super.findNameForSerialization(a);
}
})
.build();