private void reportIllegal(JsonParser parser, JsonToken expToken) throws IOException {
   JsonToken curr = parser.getCurrentToken();
   String msg = "Expected token " + expToken + "; got " + curr;
   if (curr == JsonToken.FIELD_NAME) {
     msg += " (current field name '" + parser.getCurrentName() + "')";
   }
   msg += ", location: " + parser.getTokenLocation();
   throw new IllegalStateException(msg);
 }
 @Override
 public JSONOptions deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   JsonLocation l = jp.getTokenLocation();
   //      logger.debug("Reading tree.");
   TreeNode n = jp.readValueAsTree();
   //      logger.debug("Tree {}", n);
   if (n instanceof JsonNode) {
     return new JSONOptions((JsonNode) n, l);
   } else {
     throw new IllegalArgumentException(
         String.format("Received something other than a JsonNode %s", n));
   }
 }
 @Override
 public String read(JsonParser parser) throws IOException, JsonReadException {
   try {
     String v = parser.getText();
     String error = getKeyFormatError(v);
     if (error != null) {
       throw new JsonReadException(
           "bad format for app secret: " + error, parser.getTokenLocation());
     }
     parser.nextToken();
     return v;
   } catch (JsonParseException ex) {
     throw JsonReadException.fromJackson(ex);
   }
 }