bson.ObjectId serialization with gson - java

I have a class member with type bson.ObjectId.
When serialized, gson by default uses toString() method and the returned value is not what I want. I would like to serialize ObjectId using toHexString() method instead so I could get ObjectId in HexString format.
How do I make gson to serialize ObjectId in HexString format?
Thank you.

I solved the problem.
I currently have a class like this to get Gson object and it works well for me.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.bson.types.ObjectId;
import java.lang.reflect.Type;
public class GsonUtils {
private static final GsonBuilder gsonBuilder = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.registerTypeAdapter(ObjectId.class, new JsonSerializer<ObjectId>() {
#Override
public JsonElement serialize(ObjectId src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toHexString());
}
})
.registerTypeAdapter(ObjectId.class, new JsonDeserializer<ObjectId>() {
#Override
public ObjectId deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new ObjectId(json.getAsString());
}
});
public static Gson getGson() {
return gsonBuilder.create();
}
}
Hope this helps.
Reference: http://max.disposia.org/notes/java-mongodb-id-embedded-document.html
Btw, Reference's code doesn't work and has some minor errros.
I fixed those problems in mine.

Related

Error "gson.JsonSyntaxException" when I try to retrieve a document with a date in MongoDB

In my MongoDB databse there are documents with a date field. By making a console find the result looks like:
"data" : ISODate("2015-03-01T00:40:45Z")
But when GSON try to retrieve the object appears this error:
javax.servlet.ServletException: com.google.gson.JsonSyntaxException: 03-01-2015-01-40-45-000
I tried to use the GSONBuilder as described below but the error persists:
Gson gson= new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssX").create();
How can I fix this?
I receive from server a Json Object with a long value (Timestamp) for Date.
I am creating my Gson object:
final Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new JsonDateDeserializer()).create();
This is code for my JsonDateDeserializer:
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.Date;
public class JsonDateDeserializer implements JsonDeserializer<Date> {
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
long time = json.getAsJsonPrimitive().getAsLong();
Date d = new Date(time);
return d;
}
}
Updated long time = json.getAsJsonObject().getAsJsonPrimitive("$date").getAsLong();
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.Date;
public class JsonDateDeserializer implements JsonDeserializer<Date> {
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
long time = json.getAsJsonObject().getAsJsonPrimitive("$date").getAsLong();
Date d = new Date(time);
return d;
}
}
http://www.techiesinfo.com/performance
I'm also using Gson to deserialize JSON string. For me, none of the following formats worked:
setDateFormat("yyyy-MM-dd'T'HH:mm:ssX").create(); //Didn't work
setDateFormat("yyyy-MM-dd'T'HH:mm:ssz").create(); //Didn't work
setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create(); //Didn't work
Each of them was failing to parse the date. So I just removed the last character from the format. And it worked.
setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create(); //worked
I know this is not the correct way, but at least it allows you to parse the date for the time being.
Edit: There is a better solution at this link Gson: JsonSyntaxException on date. Basically, this is the gist of the answer there:
I created a custom JsonDeserializer and registered it for the Date type. By doing so, Gson will use my deserializer for the Date type instead of its default. The same can be done for any other type if you want to serialize/deserialize it in a custom way.
public class JsonDateDeserializer implements JsonDeserializer<Date> {
public Date deserialize(JsonElement json, Type typeOfT,JsonDeserializationContext context) throws JsonParseException {
String s = json.getAsJsonPrimitive().getAsString();
long l = Long.parseLong(s.substring(6, s.length() - 2));
Date d = new Date(l);
return d;
}
}
Then, when I am creating my Gson object:
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new JsonDateDeserializer()).create();"
EDIT 2: Turns out that the logic in the deserialize() function above did not work properly. So decided to use Joda-Time library. Here is the modified function:
public class JsonDateDeserializer implements JsonDeserializer<Date> {
public Date deserialize(JsonElement json, Type typeOfT,JsonDeserializationContext context) throws JsonParseException {
String s = json.getAsJsonPrimitive().getAsString();
DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
DateTime dateTime = parser.parseDateTime(s);
return dateTime.toDate();
}
}
This is working. :)
So basically, either use the very first option, or use the last option here.
Employee employee = new GsonBuilder()
.registerTypeAdapter(LocalTime.class, new MyDateTypeAdapter())
.create().fromJson(json, Employee.class);
Change Locatime to Date orDatetime as per your requirement.
public class MyDateTypeAdapter implements JsonDeserializer<LocalTime> {
#Override
public synchronized LocalTime deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext) {
try {
JsonPrimitive dateStr= jsonElement.getAsJsonObject().getAsJsonPrimitive("$date") ;
Instant instant = Instant.parse(dateStr.getAsString());
LocalTime localTime = LocalTime.ofInstant(instant, ZoneId.of(ZoneOffset.UTC.getId()));
return localTime;
} catch (Exception e) {
log.error("error calling deserialize {}", e);
throw new JsonParseException(e);
}
}
}

REST Jackson JsonDeserialize, StackOverflowError after upgrade

In the previous version of jackson (1.9.2) the following code worked fine:
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.DeserializationContext;
...
#JsonDeserialize(using = RoleDeserializer.class)
public interface RoleDto {}
public class RoleDeserializer extends SomeSharedDeserializer<RoleDto> {}
public class SomeSharedDeserializer<T> extends JsonDeserializer<T> {
#Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
{
return jp.readValueAs(getImplementation());
}
public Class<? extends T> getImplementation(){ ... returns some generated implementation of RoleDto }
}
After we migrated to the last jackson version (1.9.13 provided by Wildfly 8.2) we got an exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of RoleDto, problem: abstract types either need to be mapped
to concrete types, have custom deserializer, or be instantiated with
additional type information
Ok, as in jackson new packages are used, we upgraded them to:
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
The deserializer is visible now (the previous exception is gone),
However, we get StackOverflowError exception. The com.fasterxml.jackson.databind.ObjectMapper reads value (line 3023):
DeserializationContext ctxt = createDeserializationContext(jp, cfg);
JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, valueType);
// ok, let's get the value
if (cfg.useRootWrapping()) {
result = _unwrapAndDeserialize(jp, ctxt, cfg, valueType, deser);
} else {
result = deser.deserialize(jp, ctxt);
}
We go to the line: result = deser.deserialize(jp, ctxt);
It causes to infinite loop and StackOverflowError as a result.
One of the way which is recommended is to implement our own SomeSharedDeserializer as:
ObjectCodec oc = jp.getCodec();
JsonNode node = oc.readTree(jp);
//here manually create new object and return it
But our classes are generated. As another solution I tried to use
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(jp, getImplementation());
But got the same result - StackOverflow exception.
How can we fix it? Can we use some deserializer, to pass it JsonParser instance, generated class that implements base interface and without StackOverflowError?
Here is you can find a full description and trials to find a solution.
The following solution has been found:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
import com.fasterxml.jackson.databind.deser.BeanDeserializerFactory;
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
import com.fasterxml.jackson.databind.type.SimpleType;
...
public abstract class RestDtoDeserializer<T> extends JsonDeserializer<T>
{
#Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
{
DeserializationConfig config = ctxt.getConfig();
SimpleType simpleType = SimpleType.construct(getImplementationClass());
BeanDescription beanDesc = config.introspect(simpleType);
BeanDeserializerFactory instance = new BeanDeserializerFactory(new DeserializerFactoryConfig());
JsonDeserializer deserializer = instance.buildBeanDeserializer(ctxt, simpleType, beanDesc);
((ResolvableDeserializer)deserializer).resolve(ctxt);
return (T) deserializer.deserialize(jp, ctxt);
}
public abstract Class<? extends T> getImplementationClass();

Jackson: Ignore whitespace in empty #XmlWrapperElement collection

Using Jackson and jackson-dataformat-xml 2.4.4, I'm trying to deserialize a XML document where a collection annotated with #XmlWrapperElement may have zero elements, but where the XML contains whitespace (in my case a line break). Jackson throws a JsonMappingException on this content with the message “Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token”. I cannot change the way the XML is produced.
Example:
static class Outer {
#XmlElementWrapper
List<Inner> inners;
}
static class Inner {
#XmlValue
String foo;
}
ObjectMapper mapper = new XmlMapper().registerModules(new JaxbAnnotationModule());
String xml = "<outer><inners>\n</inners></outer>";
Outer outer = mapper.readValue(xml, Outer.class);
The following workarounds do not work:
Enabling DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY: In this case Jackson wants to instantiate a bogus instance of Inner using the whitespace as content.
Creating setters for this field for both String and the collection type. In this case I get a JsonMappingException (“Conflicting setter definitions for property "inners"”).
In a similar Stackoverflow question it is suggested to downgrade Jackson to 2.2.3. This does not fix the problem for me.
Any suggestions?
Edit: I can work around this issue by wrapping the CollectionDeserializer and checking for a whitespace token. This looks however very fragile to me, e.g. I had to override another method to rewrap the object. I can post the workaround, but a cleaner approach would be better.
A workaround for this problem is to wrap the standard CollectionDeserializer to return an empty collection for tokens containing whitespace and register the new Deserializer. I put the code into a Module so it can be registered easily:
import java.io.IOException;
import java.util.Collection;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.std.CollectionDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;
public class XmlWhitespaceModule extends SimpleModule {
private static class CustomizedCollectionDeserialiser extends CollectionDeserializer {
public CustomizedCollectionDeserialiser(CollectionDeserializer src) {
super(src);
}
private static final long serialVersionUID = 1L;
#SuppressWarnings("unchecked")
#Override
public Collection<Object> deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
if (jp.getCurrentToken() == JsonToken.VALUE_STRING
&& jp.getText().matches("^[\\r\\n\\t ]+$")) {
return (Collection<Object>) _valueInstantiator.createUsingDefault(ctxt);
}
return super.deserialize(jp, ctxt);
}
#Override
public CollectionDeserializer createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException {
return new CustomizedCollectionDeserialiser(super.createContextual(ctxt, property));
}
}
private static final long serialVersionUID = 1L;
#Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyCollectionDeserializer(
DeserializationConfig config, CollectionType type,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (deserializer instanceof CollectionDeserializer) {
return new CustomizedCollectionDeserialiser(
(CollectionDeserializer) deserializer);
} else {
return super.modifyCollectionDeserializer(config, type, beanDesc,
deserializer);
}
}
});
}
}
After that you can add it to your ObjectMapper like this:
ObjectMapper mapper = new XmlMapper().registerModule(new XmlWhitespaceModule());

Parse JSON Object in ajax to Custom Object with JsonDeserializer

I have serialized the Object of TestDetail Class to Json using gson.
TestDetail Class--
public class TestDetail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="test_details_id")
private int testDetailsId;
#Column(name="test_exists_cc")
private byte testExistsCc;
#Column(name="test_name")
private String testName;
#Column(name="test_package")
private String testPackage;
#Column(name="test_automated_on")
private Date testAutomationDate;
//bi-directional many-to-one association to VariableDetail
#OneToMany(mappedBy="testDetail", fetch=FetchType.EAGER)
private Set<VariableDetail> variableDetails;
My Servlet Code is ---
String productSelected = request.getParameter("productSelected");
ProductDetailDAO productDetailDAO = new ProductDetailDAOImpl();
ProductDetail productDetail = productDetailDAO.getProductByName(productSelected);
Set<TestDetail> testDetailSet = productDetail.getTestDetails();
productDetailDAO.closeEntityManager();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(TestDetail.class, new TestDetailJsonSerializer());
Gson gson = builder.create();
String json = gson.toJson(testDetailSet);
//gson.fromJson(json, TestDetail.class);
System.out.println(json);
response.getWriter().write(json);
On printing the json output in consol I am getting this -
["com.amadeus.automatepckg.db.entities.TestDetail#18e4593","com.amadeus.automatepckg.db.entities.TestDetail#38a3ca","com.amadeus.automatepckg.db.entities.TestDetail#a6bcec","com.amadeus.automatepckg.db.entities.TestDetail#115a56d","com.amadeus.automatepckg.db.entities.TestDetail#89583a","com.amadeus.automatepckg.db.entities.TestDetail#6aa01a","com.amadeus.automatepckg.db.entities.TestDetail#bd5fa1","com.amadeus.automatepckg.db.entities.TestDetail#fe8ee7","com.amadeus.automatepckg.db.entities.TestDetail#7d6ca2","com.amadeus.automatepckg.db.entities.TestDetail#30c6ca","com.amadeus.automatepckg.db.entities.TestDetail#4b0a55","com.amadeus.automatepckg.db.entities.TestDetail#e89bed","com.amadeus.automatepckg.db.entities.TestDetail#10924b1","com.amadeus.automatepckg.db.entities.TestDetail#12a15d3","com.amadeus.automatepckg.db.entities.TestDetail#12c1685","com.amadeus.automatepckg.db.entities.TestDetail#1281b8c","com.amadeus.automatepckg.db.entities.TestDetail#939339","com.amadeus.automatepckg.db.entities.TestDetail#15343c2","com.amadeus.automatepckg.db.entities.TestDetail#75324a","com.amadeus.automatepckg.db.entities.TestDetail#1b9fc6","com.amadeus.automatepckg.db.entities.TestDetail#19699dd","com.amadeus.automatepckg.db.entities.TestDetail#147f26f","com.amadeus.automatepckg.db.entities.TestDetail#1f28508","com.amadeus.automatepckg.db.entities.TestDetail#a5de12","com.amadeus.automatepckg.db.entities.TestDetail#d5cfd6","com.amadeus.automatepckg.db.entities.TestDetail#18587ac","com.amadeus.automatepckg.db.entities.TestDetail#7c0a2c","com.amadeus.automatepckg.db.entities.TestDetail#16d9fe1","com.amadeus.automatepckg.db.entities.TestDetail#17fd935","com.amadeus.automatepckg.db.entities.TestDetail#6d6c90","com.amadeus.automatepckg.db.entities.TestDetail#17a765c","com.amadeus.automatepckg.db.entities.TestDetail#8d5581","com.amadeus.automatepckg.db.entities.TestDetail#102ab48","com.amadeus.automatepckg.db.entities.TestDetail#1402894","com.amadeus.automatepckg.db.entities.TestDetail#179eb02","com.amadeus.automatepckg.db.entities.TestDetail#35449e","com.amadeus.automatepckg.db.entities.TestDetail#8bed1c","com.amadeus.automatepckg.db.entities.TestDetail#1b72911","com.amadeus.automatepckg.db.entities.TestDetail#196a464","com.amadeus.automatepckg.db.entities.TestDetail#28b522","com.amadeus.automatepckg.db.entities.TestDetail#4dbd0f","com.amadeus.automatepckg.db.entities.TestDetail#ff7853","com.amadeus.automatepckg.db.entities.TestDetail#2ff65","com.amadeus.automatepckg.db.entities.TestDetail#6f03ec","com.amadeus.automatepckg.db.entities.TestDetail#976b5b","com.amadeus.automatepckg.db.entities.TestDetail#3cee0d","com.amadeus.automatepckg.db.entities.TestDetail#d150be","com.amadeus.automatepckg.db.entities.TestDetail#154e92c","com.amadeus.automatepckg.db.entities.TestDetail#bed71","com.amadeus.automatepckg.db.entities.TestDetail#fc0795","com.amadeus.automatepckg.db.entities.TestDetail#f0ce45","com.amadeus.automatepckg.db.entities.TestDetail#111a20c","com.amadeus.automatepckg.db.entities.TestDetail#b1a201","com.amadeus.automatepckg.db.entities.TestDetail#176323e","com.amadeus.automatepckg.db.entities.TestDetail#1987899","com.amadeus.automatepckg.db.entities.TestDetail#4f96a0","com.amadeus.automatepckg.db.entities.TestDetail#1fb14e","com.amadeus.automatepckg.db.entities.TestDetail#dc907a","com.amadeus.automatepckg.db.entities.TestDetail#6727f0","com.amadeus.automatepckg.db.entities.TestDetail#57e44e","com.amadeus.automatepckg.db.entities.TestDetail#91630f","com.amadeus.automatepckg.db.entities.TestDetail#cd504e","com.amadeus.automatepckg.db.entities.TestDetail#3b0790","com.amadeus.automatepckg.db.entities.TestDetail#1fee2b4","com.amadeus.automatepckg.db.entities.TestDetail#1e95777","com.amadeus.automatepckg.db.entities.TestDetail#3496c9","com.amadeus.automatepckg.db.entities.TestDetail#560854"]
Custom Serializer -
import java.lang.reflect.Type;
import com.amadeus.automatepckg.db.entities.TestDetail;
import com.google.gson.*;
public class TestDetailJsonSerializer implements JsonSerializer<TestDetail> {
#Override
public JsonElement serialize(TestDetail entity, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(entity.toString());
}
}
custom DeSerializer - TestDetailJsonSerializer
import java.lang.reflect.Type;
import com.amadeus.automatepckg.db.entities.TestDetail;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class TestDetailJonsDeSerializer implements JsonDeserializer<TestDetail> {
#Override
public TestDetail deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new TestDetail();
}
}
ajax function in jsp
$.ajax({
url: 'GetTestDetailsForProduct',
data: 'productSelected='+$("#productSelectBox").val(),
type: 'get',
dataType:'json',
success: function(result){
$(result).each(function(index,element){
alert(element); // showing object address same as console output
alert(element.testPackage); // showing undefined in alert
});
// $('#availableTests').val(jsonTestDetails);
}
Now I want to access the member variables of TestDetail from the ajax response , for this how can I parse the JSON Object back to TestDetail Object.
Replace
return new JsonPrimitive(entity.toString());
with
return new JsonPrimitive(entity);
updated:
You are right, it's a primitive presentation and it cant take object.
But still your code is building json object using String representations of entity objects, which by defaul is like 'com.package.Class#18e4593'. Thats obvious nonsense, and you need provide Object to json formatter instead of its toString() result.
And why just not use gson.toJson(obj)?

Gson not parsing Class variable

I am using Gson and I have an object that one of its fields is a Class
class A {
…
private Class aClass;
… }
When I parse the instance to Json using default Gson object aClass comes empty.
Any idea why?
You need custom type adapter. Here is example:
package com.sopovs.moradanen;
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class GsonClassTest {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Class.class, new ClassTypeAdapter())
.setPrettyPrinting()
.create();
String json = gson.toJson(new Foo());
System.out.println(json);
Foo fromJson = gson.fromJson(json, Foo.class);
System.out.println(fromJson.boo.getName());
}
public static class ClassTypeAdapter implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {
#Override
public JsonElement serialize(Class<?> src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.getName());
}
#Override
public Class<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return Class.forName(json.getAsString());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
public static class Foo {
Class<?> boo = String.class;
}
}
The output of this code is:
{
"boo": "java.lang.String"
}
java.lang.String
When I parse the instance to Json using default Gson object aClass comes empty.
Any idea why?
In a comment in issue 340, a Gson project manager explains:
Serializing types is actually somewhat of a security problem, so we don't want to support it by default. A malicious .json file could cause your application to load classes that it wouldn't otherwise; depending on your class path loading certain classes could DoS your application.
But it's quite straightforward to write a type adapter to support this in your own app.
Of course, since serialization is not the same as deserialization, I don't understand how this is an explanation for the disabled serialization, unless the unmentioned notion is to in a sense "balance" the default behaviors of serialization with deserialization.

Categories

Resources