How to use InjectableValues (for properties annotated as #JacksonInject) when using Spring RestTemplate? - jackson

Jackson's #JacksonInject annotation is useful for declaring properties of your deserialized object that are to be "injected" by the code calling for deserialization (as opposed to only being parsed from the JSON). To use this feature, it seems you have to either:
Set the InjectableValues into the ObjectMapper (which would tie them to that ObjectMapper instance and be used for all calls to it).
Get an ObjectReader [via ObjectMapper.reader(InjectableValues)] and use that ObjectReader directly to parse the JSON.
Unfortunately, neither of these is doable (from what I can see) when using Spring's RestTemplate without jumping through a lot of hoops. I don't want every object being deserialized from the RestTemplate to use injected values; nor do I see a way to customize how RestTemplate uses the underlying ObjectMapper1.
Is there a way to incorporate InjectableValues into RestTemplate's JSON deserialization?
1I suppose I could write my own custom HttpMessageConverter and figure out how to inject that into RestTemplate. But even then I don't see a way to pass the InjectableValues into ObjectMapper's read... methods. It's a lot of work even if I could.

Related

How to configure Jackson mapper

How can I globally configure json serializer for http4k? For example, snake case field names or formatting DateTime as ISO8601.
Since the ObjectMapper instance is private within ConfigurableJackson you cannot get at it after construction to do any configuration.
So you either need to construct your own direct instance of ConfigurableJackson and pass in a customized ObjectMapper or you need to subclass ConfigurableJackson with your own class. And then during the constructor, create an ObjectMapper (see example below) or intercept one being passed into your constructor and change its settings.
Whatever you do, be sure you do not break the http4k framework or anything else that might be using the same instance. You can see the defaults used by http4k declared in their source code:
object Jackson : ConfigurableJackson(ObjectMapper()
.registerModule(defaultKotlinModuleWithHttp4kSerialisers)
.disableDefaultTyping()
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(FAIL_ON_IGNORED_PROPERTIES, false)
.configure(USE_BIG_DECIMAL_FOR_FLOATS, true)
.configure(USE_BIG_INTEGER_FOR_INTS, true)
)
You can use code similar to above to create your own instance.
See this thread for some conversation about this topic: https://github.com/http4k/http4k/issues/183
You don't necessarily need to extend ConfigurableJackson - it's just that extending it is the most convenient way to do this (in our experience).
All configuration is done by tweaking the ObjectMapper instance which is injected into the ConfigurableJackson constructor - the ConfigurableJackson itself just provides the wrapper API around that mapper. The question is to do with standard configuration of Jackson, so you should seek answers to your specific questions (snake case etc) from the Jackson docs directly as http4k doesn't own that API.

Default JsonNetSerializer does not camel case property names

I'm injecting a custom serializer using NEST.JsonNetSerializer like this
var settings = new ConnectionSettings(connPool, sourceSerializer: JsonNetSerializer.Default);
When I was using the built in serializer it camel cased the property names for me (from snake case) automatically. How can I make the custom serializer work the same way? I see that I can use ConnectionSettings.DefaultFieldNameInferrer() to specify how property names are inferred. But it seems unneccessary to copy the NEST code to make it work as before.
The only reason I'm not using the built-in serializer is because I have to work with dynamic models, and the internal JSON.NET objects in NEST are inaccessible.

Using Jackson to Serialize/Deserialize a Polymorphic Map with Properties

I am currently using Guava's ForwardingMap as a base class and have numerous types that extend it. I need to maintain the Map type because instances need to be treated as such in consumers. So, even though internally the ForwardingMap using composition the external interface still has to be a map.
As a map, deserializing just key-value properties using #JsonAnyGetter and #JsonAnySetter work fine but, I also need to take into account custom properties, using #JsonProperty, which may also be a part of the instance as well.
So, when serializing or deserializing I want all of the entries and any custom properties which may be a part of the extended class.
I have looked at numerous types of solutions, such as using the Shape.OBJECT and apply interfaces, but none of them seem to work properly for me. I believe I need to create a custom deserializer/serializer to handle the bean + map processing in Jackson but cannot find any examples as to how to do this.
These links help to explain what I am trying to do with no luck:
http://www.cowtowncoder.com/blog/archives/2013/10/entry_482.html
How to serialize with Jackson a java.util.Map based class (cannot change base of ForwardingMap)
Jackson - ignore Map superclass when serializing (cannot change base because it needs to remain a Map)
Ideally, I would like an example or pointer of how to serialize and deserialize an instance that extends ForwardingMap using #JsonAnySetter and #JsonAnyGetter and has custom properties using #JsonProperty as well.
I would want my output to look like
"modules": {
"MyModel": { <-- extends ForwardingMap<>
"domain": "typeinfo",
"property":"hello", <-- comes from #JsonProperty
"another": "GoodBye", <-- comes from #JsonAnyGetter
"another2": 50 <-- comes from #JsonAnyGetter
}
}

JSON Deserialization of Interface Types without the $type "Pseudo-Property"?

It's easy to serialize an object with members that are declared as interface types - we just set the following configuration:
JsonSerializerSettings settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
};
This will create a "fake property" $type for each object, and for interface-typed data, it will be the precise type that it actually was before serialization. This makes sense because the deserializer would need to know how to rebuild it, and there's no other sure-fire way to reconstruct it, especially if you've got interfaces that have the exact same properties but different function implementations.
The following question addresses this by inspecting a property value (to determine whether it's gonna be a Son or Daughter) in a custom converter, but we can't always do this. So, we're stuck with the Newtonsoft solution with $type.
There is also a question that removes the namespace of the value of $type, which helps (by shortening), but I still don't want to make the front-end have to write the $type "property" before it gets passed to an API call.
Essentially, I want the front-end not to care about $type but at the back end (or even in an API function), I want to work with my full object as if it was never serialized (and then deserialized). How should I design my interfaces and objects? What other Newtonsoft settings do I need to make?

How can i influence instance creation for annotated serializers

I wrote a jackson module to enable a specific type of serialization. Now i want to enable global configuration of one of the new serializers. so i have to set a property on a serializer instance during creation.
Is there a way i can do that from within a jackson module?
Module interface is stateless, one-of-thing, so it does not have default wiring to affect things it adds.
But what you can do is to use a work-around; possibilities include:
use of ThreadLocal; set before serialization, read from serializer
use new (Jackson 2.3) feature of "attributes"; can set those for writing (ObjectWriter.setAttribute()) and reading (ObjectReader.setAttribute()), accessible by serializer/deserializer through context object (SerializerProvider / DeserializationContext)
So hopefully one of these works for your use case.