Jackson 2.0 Serialization config in writeValue method - java

Currently we are using Jackson 1.9.x in our application and have following code:
Object objectMapper = new ObjectMapper();
.....
SerializationConfig config = getConfig();
objectMapper.writeValue(jg, value, config);
As I understand during investigation (see SerializationConfig) in Jackson 2.0 (de)serialziation was changed and cannot be attached directly to objectMapper and my question is: What is correct replacment for the last sentence in code snippet?
Thanks in advance.

Usually you would create an ObjectWriter, and reconfigure that if necessary:
ObjectWriter w = mapper.writer(....); // various configuration methods
w.writeValue(jg, value);
Underlying configuration objects are hidden on purpose, as ObjectReader and ObjectWriter are immutable and thread-safe, so you can share and pass those instead of config objects.

Related

Two Jackson ObjectMapper generate different serializations

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

Why not make some methods in com.fasterxml.jackson.databind.ObjectMapper static?

In my project i used a lot com.fasterxml.jackson.databind.ObjectMapper to deal with JSON, for example:
ObjectMapper mapper = new ObjectMapper();
A a = mapper.readValue(file.getBytes(), A.class);
At first sight I think it's better it's better to make the readValue method static, then we can use it as ObjectMapper.readValue(), much more clear. But I know there must be some reasons that it shouldn't, does anyone know it?
Other reason is with each instance of ObjectMapper you bind certain specific confuguration ready by ObjectMapper while serialization and desrialization process somethinglike below.
So you can configure different startegies while object conversion process.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String json = mapper.writeValueAsString(new MyBean());

Jackson ObjectMapper - does changing configurations on ObjectReader impact usage of ObjectMapper by multiple threads

We have a Spring based application and we have defined a singleton bean for Jackson ObjectMapper class.
#Bean(name = "jacksonObjectMapper")
public ObjectMapper createObjectMapper() {
return new ObjectMapper();
}
We have a use case to write a generic JSON Serializer/Deserializer which we wrote in following way:
public <T, U> T deserialize(final String inputJsonString, final Class<T> targetType, final Class<U> targetParameterType) throws JsonProcessingException, IOException {
return objectMapper
.reader(objectMapper.getTypeFactory().constructParametricType(targetType, targetParameterType))
.without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.readValue(inputJsonString);
}
Here I am using ObjectReader instead of ObjectMapper itself and changing some configurations on ObjectReader (e.g. .without(...)). My question is, will such configuration changes impact other threads which may be using the same ObjectMapper instance to do something else (may be simply deserializing or serializing)?
Could someone help me understand the details and guide me?
My apologies if I haven't explained the question clearly; please let me know and I can provide further details.
Short answer: No, ObjectReader configuration does not change the underlying ObjectMapper configuration.
Explanation: If you use the ObjectMapper directly and alter the configuration of the mapper it can lead to problems if the mapper is shared between multiple threads. However, if you do not change the underlying config you should be safe anyway (more reading here).
In your case you are calling the mapper.reader(...) method where you actually create an ObjectReader. The ObjectReader and ObjectWriter are immutable and therefore they never change the underlying state. Furthermore, even if you change the config of the underlying ObjectMapper the reader will not be affected.
Note that for each call to the mapper.reader(...) method you are creating a new ObjectReader so if you change your ObjectMapper config between calls to the reader method you may run into problems.
So, to summarize: If you create an ObjectReader and use the same reader in your thread you are safe.

How can I register the Scala Jackson Module in Riak-Java?

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

How does XStream select its converters?

The only documentation on XStream converters that I can find is on these two pages:
Tutorial
List of all shipped converters
When XStream is parsing XML input, it uses a ConverterLookup (and by default, a DefaultConverterLookup) to lookup which converter to use by class. I'd like to configure my XStream mapper to use my own custom ConverterLookup, but only see a getConverterLookup() method, not a respective setter.
I have an instance where XStream is encountering a Date value in the XML, and returning using the respective DateConverter. I want it to use a different converter, which (I believe) means I need to set/register my own Converter impl. Just can't figure out how to do this. Thanks in advance.
First of all your question is in fact two unrelated questions, I'll try my best to answer them both.
Converters
To your second question regarding date conversion. Which in my mind seems to be the reason why you are here.
The basic way of adding your own converter is rather simple, the method registerConverter should give your a clue. If you are wondering how to implement a Converter I suggest you take a look at one of the many converters already provided by XStream. On an extra note I feel like I must mention the priority of converters.
The converters can be registered with an explicit priority. By
default they are registered with XStream.PRIORITY_NORMAL. Converters
of same priority will be used in the reverse sequence they have been
registered. The default converter, i.e. the converter which will be
used if no other registered converter is suitable, can be registered
with priority XStream.PRIORITY_VERY_LOW. XStream uses by default the
ReflectionConverter as the fallback converter.
In other terms, given two converters accepting the same classes, the one who was added last will be used.
ConverterLookup
To answer how you can use your ConverterLookup there are two ways which may yield the same results, personally I would go for alternative 2.
1) Overriding getConverterLookup
XStream xs = new XStream(){
#Override
public ConverterLookup getConverterLookup() {
return new ConverterLookup() {
public Converter lookupConverterForType(Class type) {
//Do your magic here
}
};
}
};
2) Using a Mapper
In this case I would keep the DefaultMapper and instead implement MapperWrapper's for my new mappings. (Have a look at buildMapper inside of XStream.java to see some of the defaults) Initialize like this:
ClassLoader classLoader = new ClassLoaderReference(new CompositeClassLoader());
Mapper mapper = new DefaultMapper(classLoader);
mapper = new MyOwnMapperWrapper(mapper);
XStream xs = new XStream(null, mapper, new XppDriver());

Categories

Resources