I have inherited some legacy code that uses Jackson 1.9.2 and am wanting to upgrade it to Jackson 2.x. One point of contention is the following:
class CustomObjectMapper extends ObjectMapper {
CustomObjectMapper(KeySerializer keySerializer) {
// StdSerializerProvider doesn't exist in Jackson 2.x
final StdSerializerProvider sp = new StdSerializerProvider();
sp.setNullValueSerializer(new NullSerializer());
sp.setDefaultKeySerializer(keySerializer);
setSerializerProvider(sp);
}
}
The trouble I am having is that StdSerializerProvider exists in Jackson 1.9.x, but not in Jackson 2.x. Is there an equivalent class for this that will preserve the existing behavior? Or is a replacement necessary at all?
The DefaultSerializerProvider must be what you're looking for. Note that they both this and the StdSerializerProvider of Jackson 1.x are subclasses of SerializerProvider. They also have very similar methods.
Note that StdSerializerProvider is a concrete class while DefaultSerializerProvider is abstract. However, you can create a new DefaultSerializerProvider.Impl to create a concrete class.
Related
I have two ObjectMapper instances of Jackson. (Using v2.8.3)
The first one is instantiated as follows:
ObjectMapper objectMapper = new ObjectMapper();
The other one is autowired from the Spring Boot context via #Autowired.
Both have the same visibility configurations like this:
But they produce different serializations for the same object. The differences I realized are as follows:
Order of the serialized fields
Serialization of protected transient fields. (The autowired instance does not serialize them at all.)
Case differences in the serialized fields i.e. the former generates "monitoringUserID" while the latter "MonitoringUserID".
What I want is that the autowired mapper would also serialize the protected transient fields.
I'd also be glad if you tell me the reasons on the other differences in both serializations.
A simplified version of an example class being serialized:
public class ClauseType implements Serializable {
protected transient List<ClauseTypeNoteItem> noteItems;
public ClauseType() {
}
public List<ClauseTypeNoteItem> getNoteItems() {
...
}
public void setNoteItems(List<ClauseTypeNoteItem> value) {
...
}
}
Complete ClauseType class: https://pastebin.com/m3h1hesn
Complete ClauseTypeNoteItem class: https://pastebin.com/dmphNV4e
Edit:
I realized that both instances had difference mapper features. According to the docs, after enabling the DEFAULT_VIEW_INCLUSION featured of the autowired instance, they had the same mapper features represented as 1068991. However the differences are still there. I also realized that the autowired mapper has two registered modules: org.springframework.boot.jackson.JsonComponentModule and com.fasterxml.jackson.datatype.joda.JodaModule. I'm not sure whether the second module has an effect on the results I'm getting.
Thanks in advance.
It turned out that Spring injects a JaxbAnnotationIntrospector coming from jackson-module-jaxb-annotations maven dependency. During the instantiations of BeanDescriptions, the Jaxb introspector overrides the visibility checker settings that I provided. So, as a solution I will inject a new ObjectMapper bean and mark it as #Primary.
If you think of any other better solution, let me know
In Spring Boot the Jackson ObjectMapper is build and customised by Jackson2ObjectMapperBuilder object. The main source of configuration are the spring.jackson.* properties as explained in the docs:
74.3 Customize the Jackson ObjectMapper
Appendix A. Common application properties
I have an API with the following return type:
class Example {
private Complex1 complex1;
private Complex2 complex2;
}
Complex1 and Complex2:
class Complex1 {
private String test1;
private String test2;
}
class Complex2 {
private String test3;
private String test4;
}
Now I would like to make use of standard serialization for Complex1 but add custom serialization for Complex2.
I tried to add a Provider for Complex2. But JAX-RS seems to be not aware of it since it is not the actual return type. If I add a Provider for Example JAX-RS makes use of my custom Provider. But having a custom Provider for Example has the drawback that I have to add logic for Complex1 too although standard serialization would be OK for Complex1.
In this example it would be OK, to do serialization for Complex1 too, but in my scenario Complex1 is huge and would like to avoid implementing serialization logic for Complex1.
Do you have any advice?
So it won't work like that. A single JSON provider is used for the entire serialization. It already knows how to serialize the entire object. There is just no way for Jackson to know that a different provider is needed mid-serialization (especially because Jackson doesn't even have any knowledge of providers, that is a JAX-RS concept).
At the Jackson level though, we can tell Jackson how to serialize with the use JsonSerializers. You can have a look at this article for writing custom serializers. Once you have the serilizer, then you can annotate Complex2 class with the custom serializer
#JsonSerialize(using = Complex2Serializer.class)
public class Complex2 {}
Heres a question for Jackson 2.3 I don't have the possibility to change to other frameworks.
I want to serialize objects to json using Jackson 2.3.
Some of the Objects are from a third party library implementing a particular (external) interface.
What I want to achieve is to prevent certain fields in those objects to be serialized.
I do not have access to modifying this class so #JsonIgnore wont cut it.
Heres an example
public interface ThirdParty{
public char[] getPassword();
public String getUser();
public Department getDepartment();
}
I'm new to Jackson, but have a feeling that it should be fairly simple to do something like this
ObjectMapper mapper=new ObjectMapper();
SimpleModule testModule = new SimpleModule("DemoModule",VersionUtil.versionFor(this.getClass()));
testModule.addSerializer(ThirdParty.class, new Some_Serializer_That_Can_Ignore_Password()));
mapper.registerModule(testModule);
(I don't think there is something called a Some_Serializer_That_Can_Ignore_Password, what I want is something that does NOT serialize the field)
I would prefer not to write a lot of code to make it work, I've seen quite verbose examples for older versions of Jackson, but none for Jackson 2.3.
Thanks!
Not really an answer for the original question, but I found a way that worked for excluding particular types, this code ensures that any StackTraceElements are not serialized.
SimpleModule testModule = new SimpleModule("DemoModule", VersionUtil.versionFor(this.getClass()));
testModule.addSerializer(StackTraceElement.class,new JsonSerializer<StackTraceElement>() {
#Override
public void serialize(StackTraceElement value, JsonGenerator jgen, SerializerProvider provider){/*Do not serialize*/}
});
mapper.registerModule(testModule);
Needed to have support for Scala Lists and Options when storing to Riak. Looks like the Scala Module for Jackson would work for this. However, how would it be hooked into the object mapper in Riak? Not sure if I need to override something or if there's an annotation that can easily solve it.
https://github.com/FasterXML/jackson-module-scala
A few releases ago I added a getObjectMapper() method to the JSONConverter as someone had requested it. This is the Converter that is used for fetch/store operations if you're passing in POJOs and haven't created and passed in your own.
You'd want to instantiate the JSONConverter yourself and get the ObjectMapper from it:
JsonConverter<MyClass> converter = new JSONConverter<MyClass>(MyClass.class, bucketName);
ObjectMapper om = converter.getObjectMapper();
You can now register the module with the ObjectMapper and then use the JSONConverter with your fetch/store operations (using the withConverter() method of the StoreObject and FetchObject).
I think that's what you're looking for. If you needed more control over serializing/deserializing your objects you could also write your own Converter- I've written a cookbook entry on the subject here: https://github.com/basho/riak-java-client/wiki/Using-a-custom-Converter
I want to convert a JSON string into java object, but the class of this object contains abstract fields, which Jackson can't instantiate, and doesn't produce the object. What is the easiest way to tell it about some default implementation of an abstract class, like
setDefault(AbstractAnimal.class, Cat.class);
or to decide about the implementation class based on JSON attribute name, eg. for JSON object:
{
...
cat: {...}
...
}
i would just wite:
setImpl("cat", Cat.class);
I know it's possible in Jackson to embed class information inside JSON, but I don't want to complicate the JSON format I use. I want to decide what class to use just by setting default implementation class, or by the attribute name ('cat') - like in XStream library, where you write:
xStream.alias("cat", Cat.class);
Is there a way to do so, especially in one line, or does it require some more code?
There are multiple ways; before version 1.8, simplest way is probably to do:
#JsonDeserialize(as=Cat.class)
public abstract class AbstractAnimal { ... }
as to deciding based on attribute, that is best done using #JsonTypeInfo, which does automatic embeddeding (when writing) and use of type information.
There are multiple kinds of type info (class name, logical type name), as well as inclusion mechanisms (as-included-property, as-wrapper-array, as-wrapper-object). This page: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization explains some of the concepts.
A full fledged answer with a very clear example can be found here: https://stackoverflow.com/a/30386694/584947
Jackson refers to this as Polymorphic Deserialization.
It definitely helped me with my issue. I had an abstract class that I was saving in a database and needed to unmarshal it to a concrete instance of a class (understandably).
It will show you how to properly annotate the parent abstract class and how to teach jackson how to pick among the available sub-class candidates at run-time when unmarshaling.
If you want to pollute neither your JSON with extra fields nor your classes with annotation, you can write a very simple module and deserializer that uses the default subclass you want. It is more than one line due to some boilerplate code, but it is still relatively simple.
class AnimalDeserializer extends StdDeserializer<Animal> {
public AnimalDeserializer() {
super(Animal.class);
}
public Animal deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
return jsonParser.readValueAs(Cat.class);
}
}
class AnimalModule extends SimpleModule {
{
addDeserializer(Animal.class, new AnimalDeserializer());
}
}
Then register this module for the ObjectMapper and that's it (Zoo is the container class that has an Animal field).
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new AnimalModule());
return objectMapper.readValue(json, Zoo.class);
The problem can be solved with the annotation #JsonDeserialize on the abstract class.
Refers to Jackson Exceptions Problems and Solutions for more info