Jackson object mapper how to ignore JsonProperty annotation? - java

I have the following scenario:
public class A {
#JsonProperty("member")
private Integer Member;
}
public class B {
private Integer Member;
}
Now, I wish to do the following:
ObjectMapper mapper = new ObjectMapper();
B b = new B(); b.setMember(1);
A a = mapper.converValue(b, A.class);
Ordinarily, this would work. However, since the objectMapper takes annotations such as #JsonProperty into account, I get the following result:
A.getMember(); // Member = NULL
There is a workaround, where all fields that are expected to be null due to this are set manually, i.e. A.setMember(b.getMember());, but this defeats the purpose of using the objectMapper in the first place and is potentially error-prone.
Is there a way to configure the objectMapper to ignore the #JsonProperty fields of a given class (or globally)?

You can configure the ObjectMapper to ignore annotations like #JsonProperty by doing:
ObjectMapper objectMapper = new ObjectMapper().configure(
org.codehaus.jackson.map.DeserializationConfig.Feature.USE_ANNOTATIONS, false)
.configure(org.codehaus.jackson.map.SerializationConfig.Feature.USE_ANNOTATIONS, false)
But this will cause it to also ignore things like #JsonIgnore etc. I'm not aware of any way to make the ObjectMapper ignore only specific annotations.

To ignore all annotations the syntax in Jackson version 2.x is:
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false)
Just ignoring a subset seems to be not possible with this approach.
But a much better solution can be found in this answer: https://stackoverflow.com/a/55064740/3351474
For your needs it should be then:
public static class IgnoreJacksonPropertyName extends JacksonAnnotationIntrospector {
#Override
protected <A extends Annotation> A _findAnnotation(Annotated annotated, Class<A> annoClass) {
if (annoClass == JsonProperty.class) {
return null;
}
return super._findAnnotation(annotated, annoClass);
}
}
...
mapper.setAnnotationIntrospector(new IgnoreJacksonPropertyName());

Related

How to ignore only #JsonSerialize annotations in combination with DefaultTyping

I have seen the many questions and answers about ignoring certain annotations, or even disabling all annotations:
.configure(MapperFeature.USE_ANNOTATIONS, false)
But
the first solution defeats DefaultTyping (types don't end up in the serialized JSON and
the second solution defeats many useful annotations, of which the most critical to us: java.beans.ConstructorProperties.
How can I ignore #JsonSerialize and still have typeinfo in my resulting JSON while still supporting other annotations such as ConstructorProperties?
Here's what I have so far:
private static ObjectMapper configureObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, JsonTypeInfo.As.PROPERTY);
mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
#Override
protected TypeResolverBuilder<?> _findTypeResolver(MapperConfig<?> config, Annotated ann, JavaType baseType) {
if (ann.hasAnnotation(JsonSerialize.class) || ann.hasAnnotation(JsonDeserialize.class)) {
return StdTypeResolverBuilder.noTypeInfoBuilder(); // or null
}
return super._findTypeResolver(config, ann, baseType);
}
});
return mapper;
}
// or the same config using a JsonMapper builder
But this still processes #JsonSerialize for some reason. I'm on jackson 2.10.0.pr3.
The real problem I'm facing is that I'm serializing 3rd party objects, which contain provided #JsonSerialize for unrelated purposes, but without defining #JsonDeserialize. Even though they're perfectly serializable without these annotations, they end up blocking our deserialization. At the same time I don't know upfront which classes they are, so these should be encoded in the resulting JSON. Furthermore, some of these objects are generated with Lombok resulting in no-arg constructors annotated with java.beans.ConstructorProperties which Jackson can deal with fine under normal circumstances.
It's the above combination of configuration I'm not able to solve.
Have you tried to override JacksonAnnotationIntrospector#findSerializer method:
class SkipSerializersJacksonAnnotationIntrospector extends JacksonAnnotationIntrospector {
private final List<Class> classesToSkip = new ArrayList<>();
public SkipSerializersJacksonAnnotationIntrospector() {
classesToSkip.add(YourClass.class);
}
#Override
public Object findSerializer(Annotated a) {
if (classesToSkip.contains(a.getRawType())) {
return null;
}
return super.findSerializer(a);
}
}
It should allow you to skip JsonSerialize annotation and keep type.

Reading #JsonIgnore field when using JacksonRabbit [duplicate]

I have class with #JsonIgnore-d field:
public class MyClass {
...
#JsonIgnore
private SomeType myfield;
...
// getters & setters
}
Is it possible to configure ObjectWriter so that it includes myfield during serialization even though being ingored?
Rationale: MyClass is serialized in many places and only in single specific one I want to have myfield.
It is possible to configure ObjectMapper to disable a JsonIgnore function. Following are some possible solution you can try with:
1.
Disable JsonIgnore function for a particular annotated field.
You can create a custom JsonIgnore annotation and a custom JacksonAnnotationIntrospector to remove the annotation from mapper context.
Following are the ideas:
Annotate #MyJsonIgnore to the fields that should be ignored while serialization:
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class MyClass {
#MyJsonIgnore
private SomeType myField;
}
#MyJsonIgnore is a simple custom annotation that wrap #JsonIgnore:
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotationsInside
#JsonIgnore
public #interface MyJsonIgnore {
}
A custom JacksonAnnotationIntrospector is implemented to remove #MyJsonIgnore from mapper context:
public class DisablingMyJsonIgnoreIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean isAnnotationBundle(final Annotation ann) {
if (ann.annotationType().equals(MyJsonIgnore.class)) {
return false;
} else {
return super.isAnnotationBundle(ann);
}
}
After that, you can set the introspector on a ObjectMapper during configuration:
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new DisablingMyJsonIgnoreIntrospector());
It results that the fields annotated with #MyJsonIgnore can be marshaled properly.
2.
Disable JsonIgnore function for the mapper
Your can create a custom JacksonAnnotationIntrospector and override hasIgnoreMarker method to always return false:
public static class DisablingJsonIgnoreIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return false;
}
}
hasIgnoreMarker is to check whether there is annotation to ignore json property. Return false will disable the JsonIngore function.
3.
Disable all annotations and specify what kinds of properties are auto-detected for a given ObjectMapper:
final ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
This simply disable all annotations.
Hope this can help.
One more option is to use the AnnotationIntrospector.nopInstance() if you want to avoid all Jackson's annotations in your pojo including #JsonIgnore e.g.
JsonMapper.builder().annotationIntrospector(AnnotationIntrospector.nopInstance()).build()...
or
new ObjectMapper().setAnnotationIntrospector(AnnotationIntrospector.nopInstance())...

Ignore some fields deserialization with jackson without changing model

I'm looking for a way to configure jackson deserializer to ignore some fields. I don't want to achieve this by annotating model since It's out given by another project; I just want to do it by constructing deserializer (ObjectMapper) to do so.
Is it possible?
You can achieve that using Mix-In annotation.
class ThirdPartyReadOnlyClass {
private String ignoredPropertyFromThirdParty;
public String getIgnoredPropertyFromThirdParty() {
return ignoredPropertyFromThirdParty;
}
}
abstract class MixIn {
#JsonIgnore
String getIgnoredPropertyFromThirdParty();
}
You can put json annotations on MixIn class as if you are putting them on original model class.
Configuring object mapper
objectMapper.addMixInAnnotations(ThirdPartyReadOnlyClass.class, MixIn.class);
you have to do following
1)write your own Deserializer which extends JsonDeserializer
2) override deserialize method and return your class object after ignoring some of the fields
3) register your deserializer with ObjectMapper
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(yourClass.class, new yourDerializer());
mapper.registerModule(module);
String newJsonString = "{\"id\":1}";
final yourClass yourClassObject= mapper.readValue(newJsonString, yourClass.class);
Hope this will solve your problem

XmlElement ignored by Jackson during serialization

i'm using Jersey to build a REST service and as Json Processor i set Jackson in my application.
#javax.ws.rs.ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("controller");
register(JacksonFeature.class);
}
I implement a ContextResolver for Jacksons ObjectMapper (as it's suggested in this post Configure Jersey/Jackson to NOT use #XmlElement field annotation for JSON field naming) which creates an ObjectMapper that doesn't fail on unknown properties during deserialization:
#Provider
public class MyJsonObjectMapperProvider implements ContextResolver<ObjectMapper> {
#Override
public ObjectMapper getContext(Class<?> type)
{
System.out.println("mapper!!!");
ObjectMapper result = new ObjectMapper();
result.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return result;
}
}
and then i register this class in my application inserting register(MyJsonObjectMapperProvider.class) in the class MyApplication shown above. I obtain what i want, in sense that if there are unknown properties in the json the object mapper doesn't fail.
My problem is another; i have this class that i use to map a specified Json, in order to deserialize it and subsequently serialize it:
public class Version {
private String status;
private String updated;
private String id;
private List<Link> links;
#XmlElement(name = "media-types")
private List<MediaTypes> media_types;
//constructor + getter and setter
}
The problem is about the element media_types and the use of the annotation #XmlElement. Before i insert the ContextResolver to personalize ObjectMapper all works fine, in fact after serialization i obtain a json in which the element/attribute media_types has as name media-types; on the contrary with ContextResolver this element doesn't change it's name and has media_types. I think that, during serialization, the annotation XmlElement doesn't work, but i'm not sure that this is the correct reason.
Another attempt i try to do is to put #JsonProperty("media-types") annotation instead of #XmlElement annotation but with no result; in fact with this annotation i obtain also a Processing Exception.
The last attempt (in addition to what has been suggested by the previous post) was that of insert these lines of code in the ContextResolver:
AnnotationIntrospector intr = new AnnotationIntrospector.Pair(new JaxbAnnotationIntrospector(),new JacksonAnnotationIntrospector());
// usually we use same introspector(s) for both serialization and deserialization:
result.getDeserializationConfig().withAnnotationIntrospector(intr);
result.getSerializationConfig().withAnnotationIntrospector(intr);
in order to use both JaxbAnnotation and JacksonAnnotation but the name of the field in question remain media_types.
I hope i was clear in explain my problem and thanks you in advance for your help!

Jackson custom type info not working

I've got classes which use an #JsonTypeIdResolver to add a custom type field to the output. This code was working as expected. I've now added an PropertyFilter to my mapper object. This is where the #JsonTypeIdResolver stopped working. The factory is not being called anymore.
Working code:
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(outputStream,myObject);
Not working code:
ObjectMapper mapper = new ObjectMapper();
PropertyFilter myfilter=new SimpleBeanFilter() {
protected boolean include(BeanPropertyWriter writer) {
return true;
}
protected boolean include(PropertyWriter writer) {
return true;
}
}
FilterProvider filters=new SimpleFilterProvider().addFilter("myFilter",myFilter);
mapper.writer(filter).writeValue(outputStream,myObject);
As the filter is just useless (accepts anything) the output should be the same. Why does my type field not get serialized anymore?
Seems like Jackson doesn't deal with inheritance the right way. My test setup was like
#JsonTypeInfo( use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "_type" )
abstract class Base {
String somefield;
...
}
class ChildA extends Base {
...
}
class ChildB extends Base {
...
}
If I write a custom serializer, which explicitely casts ChildA and ChildB to Base before serializing, it works as expected. So the basic issue is that jackson does not recognize annotations on parent objects, if not explicitly told to do so.

Categories