Using Jackson to Serialize/Deserialize a Polymorphic Map with Properties - serialization

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
}
}

Related

How to deserialize enum by implemented interface without knowing sub-classes

I am writing a custom spring boot starter that provides a uniform error response class for all repositories that will add this starter. It also provides the corresponding exception handler.
The problem is, that this error response needs an error code which might differ between all those repositories, using my starter. So the solution would be to create an error response with an error code that is an interface. Other repositories can then create enums implementing this interface to achieve the desired behavior.
It is written in kotlin
interface BaseErrorCode {
val message: String
}
class ErrorResponse {
val customMessage: String,
val errorCode: BaseErrorCode,
val timestamp: OffsetDateTime
}
Now, in another repository, I use this starter, get access to the classes above and create my error code enum:
enum class MyCustomErrorCodes : BaseErrorCode {
FOO
}
Now, I can throw an exception and through the handler, this json will be produced:
{
"customMessage": "My message",
"errorCode": "FOO",
"timestamp": "2023-01-27T12:15:31.7730645+01:00"
}
So serializing works absolutely fine.
However, when deserializing the ErrorResponse in my integration-tests, I get the following exception:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `my.package.BaseErrorCode` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (String)"{"customMessage":"My message","errorCode":"FOO","timestamp":"2023-01-27T12:12:06.4932227+01:00"}"; line: 1, column: 54] (through reference chain: my.package.ErrorResponse["errorCode"])
Approach 1
I know a solution where you write a custom deserializer. But this could not be placed in the spring boot starter because I need to know the implementing classes of that ´BaseErrorCode`-interface.
Approach 2
Using #JsonSubType, I can also tell Jackson how to handle this interface. But I do need some information about implementing enums as well, which I do not have in my starter
Is there any way to deserialize this error response
only by modifying the starter, not each repository
without knowing the classes that implement BaseErrorCode, BUT knowing that it will ALWAYS be an enum?
I think the answer lies in using intentionally dissimilar objects. I have not tested, but I think:
follow what you have with serialization, and note that you are not serializing the whole enum rather an instance of enum which conforms to BaseErrorCode.
on deserialization you make a concrete implementation of BaseErrorCode (this can be private to the Starter) that you deserialize the JSON in to. (Adding #JsonIgnoreProperties(ignoreUnknown = true) to guard against an unknown subclass sending more data than you can deal with).

Apache Ignite: type substitution on serialization

I have a class A, a cache A_CACHE and a proxy object AProxy extends A. My goal is to serialize AProxy objects as if they are A objects (automatically substitute type) and put them into A_CACHE.
Is there any way in Apache Ignite to substitute type of an object that I am trying to put into cache (serialize using BinarySerializer)?
What I have tried so far.
I have implemented and registered the same BinarySerializer for both types. I have also tried to play with BinaryNameMapper class to return the same class name for both classes, but without success. The only option that comes to my mind now is to use BinaryObjectBuilder. Is it really the only option for me?
After a small research the solution was found.
AProxy should implement writeReplace method of Serializable interface. Return proxied instance from this method. If proxied class is Serializable or Externalizable and one wants to apply custom serialization, than Binarylizable interface should be implemented by proxied class (custom binary serializers are not applied when using the hack above, but instead OptimizedMarshaller is being used).

Spring Data Rest Make an Entity Read Only by Default

I have an API exposed via Spring Data Rest which, for the most part, is read-only but which allows for updating of some properties via PATCH requests.
Is there any (I'm supposing Jackson) configuration at a global level that would essentially make an entity read only unless specific properties were annotated in some way.
I am familiar with the#JsonProperty(access = Access.READ_ONLY) Jackson annotation however would like to avoid having to annotate all read-only properties.
For example, given the class below only the field explicitly annotated would be writable. All other fields would be readable by default:
public class Thing{
private String fieldOne;
#JsonProperty(access = Access.READ_WRITE)
private String fieldTwo;
private String fieldThree;
// a lot of other properties
}
Failing any global configuration, is there anything that can be applied at the class level?
I am not aware of any way to globally set all attributes in a class to read only. Since version 2.6+ of FaserXML you can use the following annotation to at least defined the set of properties you would ignore and only allow for serialization. The following annotation would be used at the class level:
#JsonIgnoreProperties(value={ "fieldOne", "fieldThree"}, allowGetters=true)
It is not exactly what you are looking for, but arguably makes coding a little easier.

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?

BlazeDS - Conversion from ArrayList <BaseClass> on java side to Actionscript

So we have a java class with two ArrayLists of generics. It looks like
public class Blah
{
public ArrayList<ConcreteClass> a;
public ArrayList<BaseClass> b;
}
by using [ArrayElementType('ConcreteClass')] in the actionscript class, we are able to get all the "a"s converted fine. However with "b", since the actual class coming across the line is a heterogeneous mix of classes like BaseClassImplementation1, BaseClassImplementation2 etc, it gets typed as an object. Is there a way to convert it to the specific concrete class assuming that a strongly typed AS version of the java class exists on the client side
thanks for your help!
Regis
To ensure that all of your DTO classes are marshalled across AS and Java, you need to define each remote class as a "remote class" in AS by using the "RemoteClass" attribute pointing to the java class definition like this [RemoteClass(alias="com.myco.class")].
BlazeDS will perform introspection on the class as it is being serialized/de-serialized and convert it appropriately (see doc below). It doesn't matter how the classes are packed or nested in an array, as long as it can be introspected it should work.
If you need special serialization for a class you can create your own serialization proxys (called beanproxy) by extending "AbastractProxy" and loading them into blazeds using the PropertyProxyRegistry register method on startup.
You will find most of this in the Blaze developers guide http://livedocs.adobe.com/blazeds/1/blazeds_devguide/.
Creating your own beanproxy class look here: //livedocs.adobe.com/blazeds/1/javadoc/flex/messaging/io/BeanProxy.html