Bug reports and feature request: Genson 0.94

88 views
Skip to first unread message

jens.ha...@gmail.com

unread,
Feb 22, 2013, 7:46:43 PM2/22/13
to gen...@googlegroups.com
Hi Eugen,

first of all: thanks for creating this fantastic tool. I am trying to serialize very heterogeneous polymorphic objects, and where flexjson and jackson left me stranded, genson picked up.

However, I noticed a few issues, which create very unexpected errors. Please let me know if you need more detail on any of these.

1. [Bug] A class that has a "setter" with an empty parameter list leads to an exception during serialization.

Example:

class Foo {
    Integer bar;

    Integer getBar() {
        return bar;
    }

    void setBar(Integer bar) {
        this.bar = bar;
    }

    /* erroneously considered to be a setter */
    void setToNull() {
        this.bar = null;
    }
}

java.lang.ArrayIndexOutOfBoundsException: 0
    at com.owlike.genson.Genson$Builder$2.isMutator(Genson.java:799)
    at com.owlike.genson.reflect.BeanMutatorAccessorResolver$CompositeResolver.isMutator(BeanMutatorAccessorResolver.java:166)
    at com.owlike.genson.reflect.BaseBeanDescriptorProvider.provideMethodMutators(BaseBeanDescriptorProvider.java:264)
    at com.owlike.genson.reflect.BaseBeanDescriptorProvider.provideBeanPropertyMutators(BaseBeanDescriptorProvider.java:102)
    at com.owlike.genson.reflect.AbstractBeanDescriptorProvider.provide(AbstractBeanDescriptorProvider.java:51)
    at com.owlike.genson.convert.BasicConvertersFactory.provide(BasicConvertersFactory.java:109)
    at com.owlike.genson.convert.BasicConvertersFactory.create(BasicConvertersFactory.java:74)
    at com.owlike.genson.convert.BasicConvertersFactory.create(BasicConvertersFactory.java:56)
    at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
    at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
    at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
    at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
    at com.owlike.genson.convert.CircularClassReferenceConverterFactory.create(CircularClassReferenceConverterFactory.java:58)
    at com.owlike.genson.convert.CircularClassReferenceConverterFactory.create(CircularClassReferenceConverterFactory.java:22)
    at com.owlike.genson.Genson.provideConverter(Genson.java:182)
    at com.owlike.genson.Genson.serialize(Genson.java:279)
    at com.owlike.genson.Genson.serialize(Genson.java:207)

Current workaround: "Mask out" the offending setXXX method, like so:
    Genson genson = new Genson.Builder().exclude("toNull");

Suggested fix: In the isMutator method, check for the size of the parameter list and return false, so setToNull is (rightfully) no longer considered a setter.

2. [Bug] A class with a generic that implements Comparable (a fairly common case) leads to a stack overflow during deserialization, because of the self-referential generic type.

class Interval<T extends Comparable<T>> {
    T min;
    T max;
    public T getMin() { return min;}

    public T getMax() { return max;}

    public void setMin(T min) { this.min = min; }

    public void setMax(T max) { this.max = max; }
}

com.owlike.genson.TransformationException: Could not deserialize to property 'signatures' of class class ca.mda.sva.common.domain.alerts.AlertDuplicateIdentity
    at com.owlike.genson.reflect.PropertyMutator.couldNotDeserialize(PropertyMutator.java:58)
    at com.owlike.genson.reflect.PropertyMutator.deserialize(PropertyMutator.java:41)
    at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:116)
    at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:98)
    at com.owlike.genson.convert.ClassMetadataConverter.deserialize(ClassMetadataConverter.java:103)
    at com.owlike.genson.convert.NullConverter$NullConverterWrapper.deserialize(NullConverter.java:61)
    at com.owlike.genson.convert.ClassMetadataConverter.deserialize(ClassMetadataConverter.java:95)
    at com.owlike.genson.convert.NullConverter$NullConverterWrapper.deserialize(NullConverter.java:61)
    at com.owlike.genson.Genson.deserialize(Genson.java:331)
    at com.owlike.genson.Genson.deserialize(Genson.java:296)
Caused by: java.lang.StackOverflowError
    at sun.reflect.generics.reflectiveObjects.TypeVariableImpl.hashCode(Unknown Source)
    at com.owlike.genson.reflect.TypeUtil$TypeAndRootClassKey.<init>(TypeUtil.java:467)
    at com.owlike.genson.reflect.TypeUtil.expandType(TypeUtil.java:56)
    at com.owlike.genson.reflect.TypeUtil.expandType(TypeUtil.java:66)
    at com.owlike.genson.reflect.TypeUtil.expandType(TypeUtil.java:90)
    at com.owlike.genson.reflect.TypeUtil.expandType(TypeUtil.java:66)
    at com.owlike.genson.reflect.TypeUtil.expandType(TypeUtil.java:90)
    at com.owlike.genson.reflect.TypeUtil.expandType(TypeUtil.java:66)
    ....

Note: expandType() is alternately called with type=Comparable<T> and type=T.

Current workaround: Create a marker class that instantiates T with a concrete type, for each instantiating class for T used in any type to be serialized (ugly, but works for me for the time being).

Suggested fix: To break the self-referentiality, create the ExpandedParameterizedType first, and keep a HashMap of mappings
Type->corresponding ExpandedType. Don't include the type args in the constructor, but recursively expand the type arguments first,
then set them via a setter setTypeArgs(Type[] typeArgs).
Upon re-encountering the previously encountered type T (or perhaps Comparable<T>) in the recursion, close the loop by referring to the already created ExpandedParameterizedType.
(Of course, this means that you now have a circular link in your ExpandedParameterizedType hierarchy, and I am not sure what that will do to your deserialization code.)

3. [Feature Request] Allow Genson to serialize any map (currently, only HashMaps whose keys are strings are supported).

My workaround is to create a ConverterFactory for a Map<K,V>, whose converter serializes a map into an array of key-value pairs, like so:

Java:

package my.package;
HashMap<MyKeyClass, MyValueClass> myMap;

Json:

"myMap":{
  "@class":"java.util.HashMap",
  "map":[
    {"key":{"@class":"my.package.MyKeyClass","arg1":val1,"arg2":val2,...},
    "value":{"@class":"my.package.MyValueClass","arg3":val3,"arg4":val4,...}},
    ...
    {"key":{"@class":"my.package.MyKeyClass","arg1":val11,"arg2":val22,...},
    "value":{"@class":"my.package.MyValueClass","arg3":val33,"arg4":val44,...}}]}

I could make this ConverterFactory available.

Eugen Cepoi

unread,
Feb 24, 2013, 11:58:26 AM2/24/13
to gen...@googlegroups.com



Hi Eugen,

first of all: thanks for creating this fantastic tool.

Thanks :)
 

Bug fixed.
 

Yeah this is what I have done for self referencing classes in CircularClassReferenceConverterFactory, but the problem was a bit different.
Here it can happen only with generic types with their expanded representation being their upper bound. I think maybe using the rawClass of their expanded form (the upper bound) should do the work. Its what I have implemented in TypeUtil, the corresponding test cases are testCyclicGenericTypes and testGenericCyclicTypes.
 
Could you try it and confirm if it is OK? The changes are available in the repo.


3. [Feature Request] Allow Genson to serialize any map (currently, only HashMaps whose keys are strings are supported).

My workaround is to create a ConverterFactory for a Map<K,V>, whose converter serializes a map into an array of key-value pairs, like so:

Java:

package my.package;
HashMap<MyKeyClass, MyValueClass> myMap;

Json:

"myMap":{
  "@class":"java.util.HashMap",
  "map":[
    {"key":{"@class":"my.package.MyKeyClass","arg1":val1,"arg2":val2,...},
    "value":{"@class":"my.package.MyValueClass","arg3":val3,"arg4":val4,...}},
    ...
    {"key":{"@class":"my.package.MyKeyClass","arg1":val11,"arg2":val22,...},
    "value":{"@class":"my.package.MyValueClass","arg3":val33,"arg4":val44,...}}]}


Hum why not, this looks like a good solution. But I am not sure about the format, maybe : "myMap" : [ {"key": {}, "value": {}}, ...] ?
Downside it does not represent a map as a json object and class metadata would not be available (works only on json objects), on the other side it looks cleaner.
 
I could make this ConverterFactory available.



Great contributions are welcome :) google code doesn't support pull requests, but you can open an issue and attach your feature.
When all 3 points are validated I will release a new version.
 

--
You received this message because you are subscribed to the Google Groups "Genson user group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to genson+un...@googlegroups.com.
To post to this group, send email to gen...@googlegroups.com.
Visit this group at http://groups.google.com/group/genson?hl=en.
To view this discussion on the web visit https://groups.google.com/d/msg/genson/-/-8zD5rAo0WcJ.

For more options, visit https://groups.google.com/groups/opt_out.
 
 

Reply all
Reply to author
Forward
0 new messages