serialization - Create a Gson TypeAdapter for a Guava Range -


i trying serialize guava range objects json using gson, default serialization fails, , i'm unsure how correctly implement typeadapter generic type.

gson gson = new gson(); range<integer> range = range.closed(10, 20); string json = gson.tojson(range); system.out.println(json); range<integer> range2 = gson.fromjson(json,                              new typetoken<range<integer>>(){}.gettype()); system.out.println(range2); assertequals(range2, range); 

this fails so:

{"lowerbound":{"endpoint":10},"upperbound":{"endpoint":20}} passed: typetokeninterface failed: range java.lang.runtimeexception: unable invoke no-args constructor         com.google.common.collect.cut<java.lang.integer>. register         instancecreator gson type may fix problem.     @ com.google.gson.internal.constructorconstructor$12.construct(         constructorconstructor.java:210)     ... 

note default serialization loses information - fails report whether endpoints open or closed. prefer see serialized similar tostring(), e.g. [10‥20] calling tostring() won't work generic range instances, elements of range may not primitives (joda-time localdate instances, example). same reason, implementing custom typeadapter seems difficult, don't know how deserialize endpoints.

i've implemented of typeadaptorfactory based on template provided multimap ought work, i'm stuck on generics. here's have far:

public class rangetypeadapterfactory implements typeadapterfactory {   public <t> typeadapter<t> create(gson gson, typetoken<t> typetoken) {     type type = typetoken.gettype();     if (typetoken.getrawtype() != range.class         || !(type instanceof parameterizedtype)) {       return null;     }      type elementtype = ((parameterizedtype) type).getactualtypearguments()[0];     typeadapter<?> elementadapter = (typeadapter<?>)gson.getadapter(typetoken.get(elementtype));     // bound mismatch: generic method newrangeadapter(typeadapter<e>) of type     // gsonutils.rangetypeadapterfactory not applicable arguments     // (typeadapter<capture#4-of ?>). inferred type capture#4-of ? not valid     // substitute bounded parameter <e extends comparable<?>>     return (typeadapter<t>) newrangeadapter(elementadapter);   }    private <e extends comparable<?>> typeadapter<range<e>> newrangeadapter(final typeadapter<e> elementadapter) {     return new typeadapter<range<e>>() {       @override       public void write(jsonwriter out, range<e> value) throws ioexception {         if (value == null) {           out.nullvalue();           return;         }          string repr = (value.lowerboundtype() == boundtype.closed ? "[" : "(") +                       (value.haslowerbound() ? elementadapter.tojson(value.lowerendpoint()) : "-\u221e") +                       '\u2025' +                       (value.haslowerbound() ? elementadapter.tojson(value.upperendpoint()) : "+\u221e") +                       (value.upperboundtype() == boundtype.closed ? "]" : ")");         out.value(repr);       }        public range<e> read(jsonreader in) throws ioexception {         if (in.peek() == jsontoken.null) {           in.nextnull();           return null;         }          string[] endpoints = in.nextstring().split("\u2025");         e lower = elementadapter.fromjson(endpoints[0].substring(1));         e upper = elementadapter.fromjson(endpoints[1].substring(0,endpoints[1].length()-1));          return range.range(lower, endpoints[0].charat(0) == '[' ? boundtype.closed : boundtype.open,                            upper, endpoints[1].charat(endpoints[1].length()-1) == '[' ? boundtype.closed : boundtype.open);       }     };   } } 

however return (typeadapter<t>) newrangeadapter(elementadapter); line has compilation error , i'm @ loss.

what's best way resolve error? there better way serialize range objects i'm missing? if want serialize rangesets?

rather frustrating google utility library , google serialization library seem require glue work :(

this feels reinventing wheel, lot quicker put , test time spent trying gson behave, @ least presently i'll using following converters serialize range , rangeset*, rather gson.

/**  * converter between range instances , strings, custom serializer.  * ideally we'd let gson or guava us, presently cleaner.  */ public static <t extends comparable<? super t>> converter<range<t>, string> rangeconverter(final converter<t, string> elementconverter) {   final string neg_infinity = "-\u221e";   final string pos_infinity = "+\u221e";   final string dotdot = "\u2025";   return new converter<range<t>, string>() {     @override     protected string doforward(range<t> range) {       return (range.haslowerbound() && range.lowerboundtype() == boundtype.closed ? "[" : "(") +              (range.haslowerbound() ? elementconverter.convert(range.lowerendpoint()) : neg_infinity) +              dotdot +              (range.hasupperbound() ? elementconverter.convert(range.upperendpoint()) : pos_infinity) +              (range.hasupperbound() && range.upperboundtype() == boundtype.closed ? "]" : ")");     }      @override     protected range<t> dobackward(string range) {       string[] endpoints = range.split(dotdot);        range<t> ret = range.all();       if(!endpoints[0].substring(1).equals(neg_infinity)) {         t lower = elementconverter.reverse().convert(endpoints[0].substring(1));         ret = ret.intersection(range.downto(lower, endpoints[0].charat(0) == '[' ? boundtype.closed : boundtype.open));       }       if(!endpoints[1].substring(0,endpoints[1].length()-1).equals(pos_infinity)) {         t upper = elementconverter.reverse().convert(endpoints[1].substring(0,endpoints[1].length()-1));         ret = ret.intersection(range.upto(upper, endpoints[1].charat(endpoints[1].length()-1) == ']' ? boundtype.closed : boundtype.open));       }       return ret;     }   }; }  /**  * converter between rangeset instances , strings, custom serializer.  * ideally we'd let gson or guava us, presently cleaner.  */ public static <t extends comparable<? super t>> converter<rangeset<t>, string> rangesetconverter(final converter<t, string> elementconverter) {   return new converter<rangeset<t>, string>() {     private final converter<range<t>, string> rangeconverter = rangeconverter(elementconverter);     @override     protected string doforward(rangeset<t> rs) {       arraylist<string> ls = new arraylist<>();       for(range<t> range : rs.asranges()) {         ls.add(rangeconverter.convert(range));       }       return joiner.on(", ").join(ls);     }      @override     protected rangeset<t> dobackward(string rs) {       iterable<string> parts = splitter.on(",").trimresults().split(rs);       immutablerangeset.builder<t> build = immutablerangeset.builder();       for(string range : parts) {         build.add(rangeconverter.reverse().convert(range));       }       return build.build();     }   }; } 

*for inter-process communication, java serialization work fine, both classes implement serializable. i'm serializing disk more permanent storage, meaning need format can trust won't change on time. guava's serialization doesn't provide guarantee.


Comments

Popular posts from this blog

jQuery Mobile app not scrolling in Firefox -

c++ - How to add Crypto++ library to Qt project -

php array slice every 2th rule -