public static Object gsonToPrimitive(JsonElement element) {
   if (element.isJsonPrimitive()) {
     JsonPrimitive prim = element.getAsJsonPrimitive();
     if (prim.isString()) {
       return prim.getAsString();
     } else if (prim.isBoolean()) {
       return prim.getAsBoolean();
     } else if (prim.isNumber()) {
       return prim.getAsNumber();
     } else {
       throw new IllegalArgumentException("Unknown Gson primitive: " + prim);
     }
   } else if (element.isJsonArray()) {
     JsonArray array = element.getAsJsonArray();
     List<Object> list = new ArrayList<Object>();
     for (int i = 0; i < array.size(); i++) {
       list.add(gsonToPrimitive(array.get(i)));
     }
     return list;
   } else if (element.isJsonNull()) {
     return null;
   } else if (element.isJsonObject()) {
     Map<String, Object> map = new HashMap<String, Object>();
     for (Map.Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) {
       map.put(entry.getKey(), gsonToPrimitive(entry.getValue()));
     }
     return map;
   } else {
     throw new IllegalArgumentException("Unknown Gson value: " + element);
   }
 }
  public WikidataValue snakToValue(final String type, Value snak) {
    String jsonStr = null;
    try {
      jsonStr = mapper.writeValueAsString(snak);
    } catch (JsonProcessingException e) {
      throw new IllegalArgumentException("Unknown snak: " + snak);
    }
    final JsonElement element = new JsonParser().parse(jsonStr);
    final JsonElement jsonValue =
        (element.isJsonObject() && element.getAsJsonObject().has("value"))
            ? element.getAsJsonObject().get("value")
            : null;
    WikidataValue val =
        snak.accept(
            new ValueVisitor<WikidataValue>() {

              @Override
              public WikidataValue visit(EntityIdValue value) {
                if (value.getEntityType().equals(EntityIdValue.ET_ITEM)) {
                  return WikidataValue.forItem(Integer.valueOf(value.getId().substring(1)));
                } else if (value.getEntityType().equals(EntityIdValue.ET_PROPERTY)) {
                  throw new IllegalArgumentException("Did not expect entity property");
                } else {
                  throw new IllegalArgumentException(
                      "Unknown entity type: " + value.getEntityType());
                }
              }

              @Override
              public WikidataValue visit(GlobeCoordinatesValue value) {
                return new WikidataValue(type, gsonToPrimitive(jsonValue), jsonValue);
              }

              @Override
              public WikidataValue visit(QuantityValue value) {
                return new WikidataValue(type, gsonToPrimitive(jsonValue), jsonValue);
              }

              @Override
              public WikidataValue visit(StringValue value) {
                return WikidataValue.forString(value.getString());
              }

              @Override
              public WikidataValue visit(TimeValue value) {
                Calendar c =
                    new GregorianCalendar(
                        ((int) value.getYear()),
                        value.getMonth() - 1,
                        value.getDay(),
                        value.getHour(),
                        value.getMinute(),
                        value.getSecond());
                return new WikidataValue(WikidataValue.Type.TIME, c.getTime(), jsonValue);
              }

              @Override
              public WikidataValue visit(MonolingualTextValue value) {
                return WikidataValue.forString(value.getText());
              }

              @Override
              public WikidataValue visit(DatatypeIdValue value) {
                throw new IllegalArgumentException();
              }
            });
    return val;
  }