Víctor Gómez
Víctor Gómez

Reputation: 722

Convert JSON to a Vaadin Charts Theme with GSON

I have the following JSON serialized from the a Vaadin Charts default theme:

{
  "colors":[
  {
     "color":"#2f7ed8"
  },
  {
     "color":"#0d233a"
  },
  {
     "color":"#8bbc21"
  },
  {
     "color":"#910000"
  },
  {
     "color":"#1aadce"
  },
  {
     "color":"#492970"
  },
  {
     "color":"#f28f43"
  },
  {
     "color":"#77a1e5"
  },
  {
     "color":"#c42525"
  },
  {
     "color":"#a6c96a"
  }
],
"chart":{
  "backgroundcolor":{
     "color":"#FFFFFF"
  },
  "plotBackgroundcolor":{
     "color":"rgba(255,255,255,0.00)"
  },
  "plotBackgroundImage":"",
  "plotShadow":false,
  "plotBorderWidth":0,
  "plotBordercolor":{
     "color":"#C0C0C0"
  },
  "className":"",
  "style":{
     "fontFamily":"\"Lucida Grande\", \"Lucida Sans Unicode\", Verdana, Arial, Helvetica, sans-serif",
     "fontSize":"12px"
  }
},
"title":{
  "style":{
     "color":{
        "color":"#3E576F"
     },
     "fontWeight":"NORMAL",
     "fontSize":"16px"
  }
},
"subtitle":{
  "style":{
     "color":{
        "color":"#6D869F"
     },
     "fontWeight":"NORMAL",
     "fontSize":"12px"
  }
},
"xAxis":{
  "linecolor":{
     "color":"#C0D0E0"
  },
  "lineWidth":1,
  "tickcolor":{
     "color":"#C0D0E0"
  },
  "gridLinecolor":{
     "color":"#C0C0C0"
  },
  "gridLineWidth":0,
  "alternateGridcolor":{
     "color":"rgba(255,255,255,0.00)"
  },
  "title":{
     "style":{
        "color":{
           "color":"#3E576F"
        },
        "fontWeight":"NORMAL"
     }
  },
  "subtitle":{
     "style":{
        "color":{
           "color":"#666666"
        },
        "fontWeight":"NORMAL",
        "fontSize":"10px"
     }
  },
  "labels":{
     "style":{
        "color":{
           "color":"#666666"
        },
        "fontWeight":"NORMAL",
        "fontSize":"11px"
     }
  }
},
"yAxis":{
  "minorTickInterval":"NONE",
  "linecolor":{
     "color":"#C0D0E0"
  },
  "lineWidth":0,
  "tickWidth":0,
  "tickcolor":{
     "color":"#C0D0E0"
  },
  "gridLinecolor":{
     "color":"#C0C0C0"
  },
  "gridLineWidth":1,
  "alternateGridcolor":{
     "color":"rgba(255,255,255,0.00)"
  },
  "title":{
     "style":{
        "color":{
           "color":"#3E576F"
        },
        "fontWeight":"NORMAL"
     }
  },
  "subtitle":{
     "style":{
        "color":{
           "color":"#666666"
        },
        "fontWeight":"NORMAL",
        "fontSize":"10px"
     }
  },
  "labels":{
     "style":{
        "color":{
           "color":"#666666"
        },
        "fontWeight":"NORMAL",
        "fontSize":"11px"
     }
  }
},
"labels":{
  "style":{

  }
},
"legend":{
  "backgroundcolor":{
     "color":"rgba(255,255,255,0.00)"
  },
  "bordercolor":{
     "color":"#646464"
  },
  "borderRadius":5,
  "itemHiddenStyle":{
     "color":{
        "color":"#CCC"
     }
  },
  "itemHoverStyle":{
     "color":{
        "color":"#000"
     }
  },
  "itemStyle":{
     "color":{
        "color":"#3E576F"
     },
     "position":"RELATIVE"
  }
},
"tooltip":{
  "backgroundcolor":{
     "color":"rgba(255,255,255,0.85)"
  },
  "borderWidth":2,
  "followPointer":false,
  "style":{
     "color":{
        "color":"#333333"
     }
  }
},
"plotOptions":{
  "area":{
     "shadow":false
  },
  "arearange":{
     "shadow":false
  },
  "areaspline":{

  },
  "areasplinerange":{
     "shadow":false
  },
  "bar":{
     "shadow":false
  },
  "boxplot":{

  },
  "bubble":{

  },
  "column":{
     "shadow":false
  },
  "columnrange":{

  },
  "errorbar":{

  },
  "funnel":{

  },
  "gauge":{

  },
  "heatmap":{

  },
  "line":{
     "shadow":false
  },
  "pie":{
     "shadow":false
  },
  "polygon":{

  },
  "pyramid":{

  },
  "scatter":{

  },
  "series":{

  },
  "solidgauge":{

  },
  "spline":{
     "shadow":false
  },
  "treemap":{

  },
  "waterfall":{

  },
  "candlestick":{

  },
  "flags":{

  },
  "ohlc":{

  }
},
"credits":{

}
}

And this is the theme class:

/**
 * Theme class for Chart. This is empty theme, and only defines the structure of
 * Theme. Inherit own Theme class, or use Themes inherited from this class to
 * theme your Charts.
 * 
 * @see VaadinTheme
 */
public class Theme extends AbstractConfigurationObject {
    private Color[] colors; //This is an interface and is what is causing problems
    private ChartStyle chart = new ChartStyle();
    private StyleWrapper title = new StyleWrapper();
    private StyleWrapper subtitle = new StyleWrapper();
    private AxisStyle xAxis = new AxisStyle();
    private AxisStyle yAxis = new AxisStyle();
    private StyleWrapper labels = new StyleWrapper();
    private LegendStyle legend = new LegendStyle();
    private TooltipStyle tooltip = new TooltipStyle();
    private PlotOptionsStyle plotOptions = new PlotOptionsStyle();
    private Credits credits = new Credits();

    //Getters and setters
}

The idea is to convert a JSON like that to a Vaadin Charts theme in order to allow the admin of my application to theme the charts. However GSON throws the following exception:

Caused by: java.lang.RuntimeException: Unable to invoke no-args constructor for interface com.vaadin.addon.charts.model.style.Color. Register an InstanceCreator with Gson for this type may fix this problem.
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:226)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:207)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:72)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
at com.google.gson.Gson.fromJson(Gson.java:861)
at com.google.gson.Gson.fromJson(Gson.java:799)
at es.cic.luca.web.vaadin.elementos.GeneradorGrafica.crearThemeFromJson(GeneradorGrafica.java:1214)
at es.cic.luca.web.vaadin.elementos.GeneradorGrafica.generar(GeneradorGrafica.java:93)
at es.cic.luca.web.vaadin.vista.CreacionGraficasVista.lambda$1(CreacionGraficasVista.java:426)
at es.cic.luca.web.vaadin.vista.CreacionGraficasVista$$Lambda$82/1320668893.buttonClick(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508)
... 83 more

Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:48)
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223)
... 99 more

Caused by: java.lang.InstantiationException: com.vaadin.addon.charts.model.style.Color
at sun.misc.Unsafe.allocateInstance(Native Method)
... 105 more

I created the class ColorInstanceCreator to solve the problem:

public class ColorInstanceCreator implements InstanceCreator<Color> {

    @Override
    public Color createInstance(Type type) {
        return new SolidColor("");
    }
}

And make GSON to use it:

Gson gson = new GsonBuilder().registerTypeAdapter(Color.class,new ColorInstanceCreator()).create();

This solves the problem but all the colors in the converted class are black (#000000).

I also tried to create a custom serializer/deserializer the I found here, but it doesn't work:

Caused by: com.google.gson.JsonParseException: no 'type' member found in what was expected to be an interface wrapper
at es.cic.luca.web.vaadin.elementos.GeneradorGrafica$InterfaceAdapter.get(GeneradorGrafica.java:1248)
at es.cic.luca.web.vaadin.elementos.GeneradorGrafica$InterfaceAdapter.deserialize(GeneradorGrafica.java:1231)
at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:72)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
at com.google.gson.Gson.fromJson(Gson.java:861)
at com.google.gson.Gson.fromJson(Gson.java:799)
at es.cic.luca.web.vaadin.elementos.GeneradorGrafica.crearThemeFromJson(GeneradorGrafica.java:1213)
at es.cic.luca.web.vaadin.elementos.GeneradorGrafica.generar(GeneradorGrafica.java:93)
at es.cic.luca.web.vaadin.vista.CreacionGraficasVista.lambda$1(CreacionGraficasVista.java:426)
at es.cic.luca.web.vaadin.vista.CreacionGraficasVista$$Lambda$124/1623517905.buttonClick(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508)
... 83 more

What more can I do to solve my problem?

Upvotes: 0

Views: 237

Answers (1)

V&#237;ctor G&#243;mez
V&#237;ctor G&#243;mez

Reputation: 722

I adapted this code to solve my problem and here is the solution:

final class ColorAdapter implements JsonDeserializer<Color> {

    public Color deserialize(JsonElement elem, Type interfaceType,
            JsonDeserializationContext context) throws JsonParseException {
        Color toReturn = null;
        if(elem instanceof JsonPrimitive) {
            final JsonPrimitive color = elem.getAsJsonPrimitive();
            toReturn = new SolidColor(color.getAsString());
        } else {
            final JsonObject wrapper = (JsonObject) elem;
            final JsonElement data = get(wrapper, "color");
            toReturn = context.deserialize(data, Color.class);
        }
        return toReturn;
    }

    private JsonElement get(final JsonObject wrapper, String memberName) {
        final JsonElement elem = wrapper.get(memberName);
        if (elem == null)
            throw new JsonParseException(
                    "no '"
                            + memberName
                            + "' member found in what was expected to be an interface wrapper");
        return elem;
    }
}

Upvotes: 1

Related Questions