Serializing / deserializing optionals with Morphia - java

I need Morphia to support serialization of java 8 Optional. Morphia clearly doesn't special case Optional, and, by default, Morphia seems to serialize an Optional with a value to {value: BLAH} and to drop an empty Optional (as I have dropEmpty or whatever configured).
When I attempt to rehydrate an Optional containing an enum though, Morphia fails with a class cast exception in the bowels of the mapping logic:
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb.DBObject
at org.mongodb.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:160)
Indeed, Morphia seems to be losing type information; when I implemented my own TypeConverter, the MappedField contained no subClass information, which is where I'd normally look for information for the information. Instead, I had to store class information about the inner value in a separate field so that the result ends up looking like:
{"valueClassName" : "full.class.name" "value" : BLAH}.
Is there a more elegant way of handling this? This pretty much seems like a special case of IterableConverter (although that clearly depends on the subClass value being present within MappedField as well.
For what it's worth, 'upgrading morphia' isn't much of an option, because of the myriad bugs that erupt whenever we try to do so. This was failing with org.mongodb.morphia version 0.108

Related

jOOQ: when fetching into a Enum field, how to ensure it throws an exception if the value cannot mapped

We use jOOQ 3.15.4 with Spring Boot 2.6.2
We have an enum stored as a string in database. It looks like this in the generated code:
public final TableField<StatusRecord, String> STATUS = createField(DSL.name("status"), SQLDataType.VARCHAR(255).nullable(false), this, "");
When reading it, we fetch into an object with #Column annotations:
#Column(name = "status")
StatusEnum status
The behavior we see is that when we have a string in DB that does not correspond to any value of the enum, the status field in the object that we map into is null.
Is there a way to have this type safe, and have a MappingException thrown when the string cannot be mapped to the enum, like the standard behavior of the valueOf method of an enum ?
The topic has been discussed a few times in jOOQ's issue tracker, mailing list, etc. There's a pending feature request to change the current behaviour of ignoring inconvertible values to throwing exceptions, see e.g. https://github.com/jOOQ/jOOQ/issues/3377
It wasn't easy to do in the past without breaking compatibility as the conversions were implemented in static methods. But since jOOQ 3.14, we have a ConverterProvider SPI, so it might be possible to make this configurable, and gradually move towards a fail-fast strategy.
Having said so, you can implement your own ConverterProvider and add such checks to it. Alternatively, you can attach a custom Converter to your Field using code generation configuration, and let it throw whenever an invalid value is mapped.

Is there a way of GSON to be "not lenient" at all?

It seems that GSON silently ignores when a JSON string contains field names that don't match the target POJO class. One solution outlined here suggests to use annotations to mark "required" fields to have GSON fail when de-serializing strings that don't contain fields.
But we defined that our POJOs must be "exact" matches (when we allow for incoming objects to be null, they must be declared as Optional field in the POJO - and we have a special type adapter that turns nulls into Optional.empty() instances). Therefore all fields in the POJO are mandatory. And null isn't a valid value.
Following the guidance in that question I linked to, it seems that the only way of having gson fail while parsing: to do a full "deep reflection" scan of the object created by de-serialization process and check if any of the Optional fields are null.
Or maybe - I am missing something and there is an easier way to have gson tell me when our JSON strings contain bad field names?
( background: we just ran into a problem because of wrong field name deep down in a nested structure - leading to null objects where we didn't expect them )
Turns out: this "deficiency" is really a core design point of gson: it is a JSON parser. Validation is not within the scope of gson.
Therefore the "correct" answer is to use java bean validation annotations and to put some implementation framework (for example the hibernate validator or apache bval) in place.
Alternatively, it is possible to register a special type adapter when creating the gson instance. This type adapter uses reflection to override an internal map with a bit of checking code - allowing for a relatively "clean" solution which leads to gson throwing an exception when running into "unknown" fields. ( thanks to Andy Turner for pointing to the corresponding github issue tracker entry --- code can be found there)

Custom serialize and deserialize to create JSON

I have a class with 2 values: val1 and val2. I am sending val1 to register (create) API and val2 is auto filled by API itself. I do not want to send val2 while calling create API and that API is not designed for handling unwanted values.
In short I want to ignore val2 while I call create API but I want it while I call get API.
The code that I have right now creates JSON including both the values assigning null to val2. This causes that API to throw an exception.
Is there any easy way of doing it (java /groovy)?
Is there any easy way of doing it (java /groovy)?
Not 100% sure I'm understanding your need. I believe it depends on what json de/serializer you are using. For example, using Jackson we do:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonTypeName("account")
public class Account {
I believe this allows us to load in objects with a ton of extra json fields into objects without corresponding java fields. To quote from the javadocs:
Property that defines whether it is ok to just ignore any unrecognized properties during deserialization. If true, all properties that are unrecognized -- that is, there are no setters or creators that accept them -- are ignored without warnings (although handlers for unknown properties, if any, will still be called) without exception.

Does XStream support cyclic JSON graphs?

I have an object containing cyclic references. According to the XStream Json documentation, cyclic references are NOT supported, and one should therefore use the NO_REFERENCES XStream mode when marshalling an object to Json:
What limitations has XStream's JSON support?
JSON represents a very simple data model for easy data transfer.
Especially it has no equivalent for XML attributes. Those are written
with a leading "#" character, but this is not always possible without
violating the syntax (e.g. for array types). Those may silently
dropped (and makes it therefore difficult to implement
deserialization). References are another issue in the serialized
object graph, since JSON has no possibility to express such a
construct. You should therefore always set the NO_REFERENCES mode of
XStream. Additionally you cannot use implicit collections, since the
properties in a JSON object must have unique names.
But I tried setting the mode to ID_REFERENCES and it appears as though the Object is marshalled with references, and the object can be unmarshalled properly. Is the XStream documentation simply outdated, or have I simply inadvertently created the object graph in such a way that I haven't hit any of the limitations?
Sorry, but I can't post my exact graph as an example as it contains application/domain-specific code and it might take some time to construct a 'clean' alternative.

How to handle dynamic JSON data with GWT Autobeans?

Currently I have a class setup to be processed as an autobean:
public interface Asset extends Hit {
String getGuid();
String getHitType();
Map<String,Serializable> getMetadata();
}
I tried using Object instead of Serializable:
Map<String,Object> getMetadata()
but this seems to blow up when trying to access data (because it's not 'reified').
The Metadata map may contain other maps, strings, ints, etc. How do I retrieve data from an inner map of that metadata object?
Currently, if I call asset.getMetadata().get("title"); this returns a SerializableAutoBean and performing toString() or String.valueOf(obj) on that object returns the in memory object information and not the actually string value.
Can an AutoBean object be this dynamic, or do you specifically have to define every field?
AutoBeans aren't "dynamic" in the Java generics or RTTI sense.
In GWT, all types have to be known at compile time for anything which is auto-generated (which includes AutoBeans). This places restrictions on your designs which don't allow you to take full advantage of Java's language features (specifically, generics and other RTTI features). So, AutoBeans are not dynamic in the RTTI or Java generic sense. However, AutoBeans are simply a low-level way of wrapping your data, and you still have access to the data by using Splittables!
As stated in the previous comments, you can use Splittables for the parts of your JSON object whose type is not known at serialization/decode time. Sure, it would be nice to have everything happen at once, but nothing is stopping you from performing some post-processing on your data objects to get them into your desired state.
A really good way for someone to "Grok" what is going on with AutoBeans (and anything else which is autogenerated) is to look at the resulting generated code. The default location for maven is: ${project.build.directory}/.generated.
If you look in there after you've compiled, you should find the code which the GWT compiler produces for your AutoBeans.

Categories

Resources