@Override
  public SchemaAndValue toConnectData(String topic, byte[] value) {
    JsonNode jsonValue;
    try {
      jsonValue = deserializer.deserialize(topic, value);
    } catch (SerializationException e) {
      throw new DataException(
          "Converting byte[] to Kafka Connect data failed due to serialization error: ", e);
    }

    if (enableSchemas
        && (jsonValue == null
            || !jsonValue.isObject()
            || jsonValue.size() != 2
            || !jsonValue.has("schema")
            || !jsonValue.has("payload")))
      throw new DataException(
          "JsonDeserializer with schemas.enable requires \"schema\" and \"payload\" fields and may not contain additional fields");

    // The deserialized data should either be an envelope object containing the schema and the
    // payload or the schema
    // was stripped during serialization and we need to fill in an all-encompassing schema.
    if (!enableSchemas) {
      ObjectNode envelope = JsonNodeFactory.instance.objectNode();
      envelope.set("schema", null);
      envelope.set("payload", jsonValue);
      jsonValue = envelope;
    }

    return jsonToConnect(jsonValue);
  }
Example #2
0
  @Override
  public void execute() throws MojoExecutionException {
    try {
      JavaProjectBuilder builder = new JavaProjectBuilder();
      builder.addSourceTree(new File(srcDirectory, "src/main/java"));

      ObjectNode root = initializeRoot();
      ArrayNode tags = mapper.createArrayNode();
      ObjectNode paths = mapper.createObjectNode();

      root.set("tags", tags);
      root.set("paths", paths);

      builder.getClasses().forEach(jc -> processClass(jc, paths, tags));

      if (paths.size() > 0) {
        getLog().info("Generating ONOS REST API documentation...");
        genCatalog(root);

        if (!isNullOrEmpty(apiPackage)) {
          genRegistrator();
        }
      }

      project.addCompileSourceRoot(new File(dstDirectory, GEN_SRC).getPath());

    } catch (Exception e) {
      getLog().warn("Unable to generate ONOS REST API documentation", e);
      throw e;
    }
  }
 public String parseData(JsonNode node, String f)
     throws JsonProcessingException, IOException, JSONException {
   System.out.println("---");
   ObjectNode json = factory.objectNode();
   type.push(f);
   Iterator<String> fieldNames = node.fieldNames();
   String uri = type.toString().replaceAll(", ", ".").replaceAll("[\\[\\]]", "");
   json.put("type_uri", uri);
   ObjectNode object = factory.objectNode();
   while (fieldNames.hasNext()) {
     String fieldName = fieldNames.next();
     JsonNode fieldValue = node.get(fieldName);
     // if (node.findParent("description").get("description") != null)
     // json.set("value", node.findParent("description").get("description"));
     if (fieldValue.isObject()) {
       ObjectNode assoc = factory.objectNode();
       assoc.set(uri + "." + parseData(fieldValue, fieldName).replaceAll("\n", ""), fieldValue);
       json.set("composite", assoc);
     } else {
       json.set(fieldName, fieldValue);
     }
   }
   // json.append("}");
   System.out.println("xxx");
   System.out.println(m.writerWithDefaultPrettyPrinter().writeValueAsString(json));
   TopicModel t = new TopicModel(new JSONObject(json.toString()));
   System.err.println(t.getUri());
   System.err.println(t.getChildTopicsModel());
   return type.pop();
 }
 public JsonNode getSchema(SerializerProvider paramSerializerProvider, Type paramType)
     throws JsonMappingException {
   ObjectNode localObjectNode = createSchemaNode("array", true);
   if (paramType != null) {
     paramType = paramSerializerProvider.constructType(paramType);
     if (paramType.isArrayType()) {
       paramType = ((ArrayType) paramType).getContentType().getRawClass();
       if (paramType != Object.class) {
         break label54;
       }
       localObjectNode.set("items", JsonSchema.getDefaultSchemaNode());
     }
   }
   return localObjectNode;
   label54:
   paramType = paramSerializerProvider.findValueSerializer(paramType, this._property);
   if ((paramType instanceof SchemaAware)) {}
   for (paramSerializerProvider =
           ((SchemaAware) paramType).getSchema(paramSerializerProvider, null);
       ;
       paramSerializerProvider = JsonSchema.getDefaultSchemaNode()) {
     localObjectNode.set("items", paramSerializerProvider);
     return localObjectNode;
   }
 }
Example #5
0
  // Processes parameters of javaMethod and enters the proper key-values into the methodNode
  private void processParameters(JavaMethod javaMethod, ObjectNode methodNode) {
    ArrayNode parameters = mapper.createArrayNode();
    methodNode.set("parameters", parameters);
    boolean required = true;

    for (JavaParameter javaParameter : javaMethod.getParameters()) {
      ObjectNode individualParameterNode = mapper.createObjectNode();
      Optional<JavaAnnotation> optional =
          javaParameter
              .getAnnotations()
              .stream()
              .filter(
                  annotation ->
                      annotation.getType().getName().equals(PATH_PARAM)
                          || annotation.getType().getName().equals(QUERY_PARAM))
              .findAny();
      JavaAnnotation pathType = optional.isPresent() ? optional.get() : null;

      String annotationName = javaParameter.getName();

      if (pathType != null) { // the parameter is a path or query parameter
        individualParameterNode.put(
            "name", pathType.getNamedParameter("value").toString().replace("\"", ""));
        if (pathType.getType().getName().equals(PATH_PARAM)) {
          individualParameterNode.put("in", "path");
        } else if (pathType.getType().getName().equals(QUERY_PARAM)) {
          individualParameterNode.put("in", "query");
        }
        individualParameterNode.put("type", getType(javaParameter.getType()));
      } else { // the parameter is a body parameter
        individualParameterNode.put("name", annotationName);
        individualParameterNode.put("in", "body");

        // TODO add actual hardcoded schemas and a type
        // body parameters must have a schema associated with them
        ArrayNode schema = mapper.createArrayNode();
        individualParameterNode.set("schema", schema);
      }
      for (DocletTag p : javaMethod.getTagsByName("param")) {
        if (p.getValue().contains(annotationName)) {
          try {
            String description = p.getValue().split(" ", 2)[1].trim();
            if (description.contains("optional")) {
              required = false;
            }
            individualParameterNode.put("description", description);
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
      individualParameterNode.put("required", required);
      parameters.add(individualParameterNode);
    }
  }
Example #6
0
  // Temporary solution to add responses to a method
  // TODO Provide annotations in the web resources for responses and parse them
  private void addResponses(ObjectNode methodNode) {
    ObjectNode responses = mapper.createObjectNode();
    methodNode.set("responses", responses);

    ObjectNode success = mapper.createObjectNode();
    success.put("description", "successful operation");
    responses.set("200", success);

    ObjectNode defaultObj = mapper.createObjectNode();
    defaultObj.put("description", "Unexpected error");
    responses.set("default", defaultObj);
  }
Example #7
0
  private void processRestMethod(
      JavaMethod javaMethod,
      String method,
      Map<String, ObjectNode> pathMap,
      String resourcePath,
      ArrayNode tagArray,
      ObjectNode definitions) {
    String fullPath = resourcePath, consumes = "", produces = "", comment = javaMethod.getComment();
    DocletTag tag = javaMethod.getTagByName("rsModel");
    for (JavaAnnotation annotation : javaMethod.getAnnotations()) {
      String name = annotation.getType().getName();
      if (name.equals(PATH)) {
        fullPath = resourcePath + "/" + getPath(annotation);
        fullPath = fullPath.replaceFirst("^//", "/");
      }
      if (name.equals(CONSUMES)) {
        consumes = getIOType(annotation);
      }
      if (name.equals(PRODUCES)) {
        produces = getIOType(annotation);
      }
    }
    ObjectNode methodNode = mapper.createObjectNode();
    methodNode.set("tags", tagArray);

    addSummaryDescriptions(methodNode, comment);
    addJsonSchemaDefinition(definitions, tag);
    addJsonSchemaDefinition(definitions, tag);

    processParameters(javaMethod, methodNode, method, tag);

    processConsumesProduces(methodNode, "consumes", consumes);
    processConsumesProduces(methodNode, "produces", produces);
    if (tag == null
        || ((method.toLowerCase().equals("post") || method.toLowerCase().equals("put"))
            && !(tag.getParameters().size() > 1))) {
      addResponses(methodNode, tag, false);
    } else {
      addResponses(methodNode, tag, true);
    }

    ObjectNode operations = pathMap.get(fullPath);
    if (operations == null) {
      operations = mapper.createObjectNode();
      operations.set(method, methodNode);
      pathMap.put(fullPath, operations);
    } else {
      operations.set(method, methodNode);
    }
  }
 private ObjectNode mapsJson() {
   ObjectNode payload = objectNode();
   ArrayNode order = arrayNode();
   ObjectNode maps = objectNode();
   payload.set(ORDER, order);
   payload.set(MAPS, maps);
   SUPPORTED_MAPS.forEach(
       m -> {
         maps.set(
             m.id,
             objectNode().put(MAP_ID, m.id).put(DESCRIPTION, m.description).put(SCALE, m.scale));
         order.add(m.id);
       });
   return payload;
 }
Example #9
0
 private void processConsumesProduces(ObjectNode methodNode, String type, String io) {
   if (!io.equals("")) {
     ArrayNode array = mapper.createArrayNode();
     methodNode.set(type, array);
     array.add(io);
   }
 }
Example #10
0
  // Checks whether a class's methods are REST methods and then places all the
  // methods under a specific path into the paths node
  private void processAllMethods(
      JavaClass javaClass, String resourcePath, ObjectNode paths, ArrayNode tagArray) {
    // map of the path to its methods represented by an ObjectNode
    Map<String, ObjectNode> pathMap = new HashMap<>();

    javaClass
        .getMethods()
        .forEach(
            javaMethod -> {
              javaMethod
                  .getAnnotations()
                  .forEach(
                      annotation -> {
                        String name = annotation.getType().getName();
                        if (name.equals(POST)
                            || name.equals(GET)
                            || name.equals(DELETE)
                            || name.equals(PUT)) {
                          // substring(12) removes "javax.ws.rs."
                          String method =
                              annotation.getType().toString().substring(12).toLowerCase();
                          processRestMethod(javaMethod, method, pathMap, resourcePath, tagArray);
                        }
                      });
            });

    // for each path add its methods to the path node
    for (Map.Entry<String, ObjectNode> entry : pathMap.entrySet()) {
      paths.set(entry.getKey(), entry.getValue());
    }
  }
 @RequestMapping("/drug/enforcements")
 @ResponseBody
 public JsonNode getDrugRecallsForUnii(
     @RequestParam(value = "unii", defaultValue = "") String unii,
     @RequestParam(value = "limit", defaultValue = "0") int limit)
     throws Exception {
   JsonNode node;
   HttpHeaders headers = new HttpHeaders();
   ObjectMapper mapper = new ObjectMapper();
   headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
   UriComponentsBuilder builder =
       UriComponentsBuilder.fromHttpUrl(searchDrugEnfrcmntUrl)
           .queryParam("limit", uniiRecallsLimit);
   this.apiKey.addToUriComponentsBuilder(builder);
   if (unii != null && unii.trim().length() > 0) {
     builder.queryParam("search", "openfda.unii:" + unii);
     try {
       node = mapper.readTree(rest.getForObject(builder.build().toUri(), String.class));
       ((ObjectNode) node).set("results", getSortedResults(node.get("results"), limit));
     } catch (HttpClientErrorException ex) {
       if (ex.getStatusCode().value() == 404) {
         node =
             new ObjectMapper()
                 .readTree(
                     "{\"error\":{\"code\":\"NOT_FOUND\", \"message\":\"No matches found!\"}}");
       } else {
         throw ex;
       }
     }
   } else {
     node = getDrugRecalls(limit == 0 ? 10 : limit, null, null);
   }
   return node;
 }
Example #12
0
 /** Returns a JSON representation of this */
 @Override
 public JsonNode toJson() {
   ObjectNode node = getFactory().objectNode();
   node.put("entity", entityVersion.getEntity());
   if (entityVersion.getVersion() != null) node.put("entityVersion", entityVersion.getVersion());
   if (client != null) {
     node.set("client", client.toJson());
   }
   if (execution != null) {
     node.set("execution", execution.toJson());
   }
   if (getOperation() != null) {
     node.put("op", getOperation().name());
   }
   return node;
 }
  /**
   * Sends a message envelope on this socket
   *
   * @param envelope The message envelope
   * @return This socket instance
   * @throws IOException Thrown if the message cannot be sent
   */
  public Socket push(final Envelope envelope) throws IOException {
    LOG.log(Level.FINE, "Pushing envelope: {0}", envelope);
    final ObjectNode node = objectMapper.createObjectNode();
    node.put("topic", envelope.getTopic());
    node.put("event", envelope.getEvent());
    node.put("ref", envelope.getRef());
    node.set(
        "payload",
        envelope.getPayload() == null ? objectMapper.createObjectNode() : envelope.getPayload());
    final String json = objectMapper.writeValueAsString(node);
    LOG.log(Level.FINE, "Sending JSON: {0}", json);

    RequestBody body = RequestBody.create(WebSocket.TEXT, json);

    if (this.isConnected()) {
      try {
        webSocket.sendMessage(body);
      } catch (IllegalStateException e) {
        LOG.log(Level.SEVERE, "Attempted to send push when socket is not open", e);
      }
    } else {
      this.sendBuffer.add(body);
    }

    return this;
  }
Example #14
0
  // Temporary solution to add responses to a method
  private void addResponses(ObjectNode methodNode, DocletTag tag, boolean responseJson) {
    ObjectNode responses = mapper.createObjectNode();
    methodNode.set("responses", responses);

    ObjectNode success = mapper.createObjectNode();
    success.put("description", "successful operation");
    responses.set("200", success);
    if (tag != null && responseJson) {
      ObjectNode schema = mapper.createObjectNode();
      tag.getParameters().stream().forEach(param -> schema.put("$ref", "#/definitions/" + param));
      success.set("schema", schema);
    }

    ObjectNode defaultObj = mapper.createObjectNode();
    defaultObj.put("description", "Unexpected error");
    responses.set("default", defaultObj);
  }
Example #15
0
 @Override
 public ObjectNode build() {
   ObjectNode root = JsonNodeFactory.instance.objectNode();
   Iterator<Map.Entry<String, AggsObject>> it = buckets.entrySet().iterator();
   while (it.hasNext()) {
     Map.Entry<String, AggsObject> bucket = it.next();
     root.set(bucket.getKey(), bucket.getValue().build());
   }
   return root;
 }
  /** Override this to place result in non-standard location on document */
  protected ObjectNode setEntityToExtend(ObjectNode rootDocument, ActivityObject activityObject) {

    if (this.configuration.getEntity().equals(HttpProcessorConfiguration.Entity.ACTIVITY))
      return mapper.convertValue(activityObject, ObjectNode.class);
    else
      rootDocument.set(
          this.configuration.getEntity().toString(),
          mapper.convertValue(activityObject, ObjectNode.class));

    return rootDocument;
  }
  @Test
  public void givenANode_whenModifyingIt_thenCorrect() throws IOException {
    final String newString = "{\"nick\": \"cowtowncoder\"}";
    final JsonNode newNode = mapper.readTree(newString);

    final JsonNode rootNode = ExampleStructure.getExampleRoot();
    ((ObjectNode) rootNode).set("name", newNode);

    assertFalse(rootNode.path("name").path("nick").isMissingNode());
    assertEquals("cowtowncoder", rootNode.path("name").path("nick").textValue());
  }
Example #18
0
 /**
  * Get details of a specified port pair id.
  *
  * @param id port pair id
  * @return 200 OK, 404 if given identifier does not exist
  */
 @GET
 @Path("{pair_id}")
 @Produces(MediaType.APPLICATION_JSON)
 public Response getPortPair(@PathParam("pair_id") String id) {
   PortPair portPair =
       nullIsNotFound(
           get(PortPairService.class).getPortPair(PortPairId.of(id)), PORT_PAIR_NOT_FOUND);
   ObjectNode result = mapper().createObjectNode();
   result.set("port_pair", codec(PortPair.class).encode(portPair, this));
   return ok(result.toString()).build();
 }
Example #19
0
 @Override
 public DataSourceImpl getNestedOrSetEmpty(String attrName) {
   JsonNode json = data.get(attrName);
   if (json == null) {
     json = data.objectNode();
     data.set(attrName, json);
   } else if (!json.isObject()) {
     throw new ConfigException("Attribute " + attrName + " must be an object");
   }
   return newInstance(model, (ObjectNode) json);
 }
Example #20
0
  // initializes top level root with Swagger required specifications
  private ObjectNode initializeRoot() {
    ObjectNode root = mapper.createObjectNode();
    root.put("swagger", "2.0");
    ObjectNode info = mapper.createObjectNode();
    root.set("info", info);

    root.put("basePath", webContext);
    info.put("version", apiVersion);
    info.put("title", apiTitle);
    info.put("description", apiDescription);

    ArrayNode produces = mapper.createArrayNode();
    produces.add("application/json");
    root.set("produces", produces);

    ArrayNode consumes = mapper.createArrayNode();
    consumes.add("application/json");
    root.set("consumes", consumes);

    return root;
  }
 /**
  * Retrieve details of a specified path id.
  *
  * @param id path id
  * @return 200 OK, 404 if given identifier does not exist
  */
 @GET
 @Path("{path_id}")
 @Produces(MediaType.APPLICATION_JSON)
 public Response queryPath(@PathParam("path_id") String id) {
   log.debug("Query path by identifier {}.", id);
   Tunnel tunnel =
       nullIsNotFound(get(PceService.class).queryPath(TunnelId.valueOf(id)), PCE_PATH_NOT_FOUND);
   PcePath path = DefaultPcePath.builder().of(tunnel).build();
   ObjectNode result = mapper().createObjectNode();
   result.set("path", codec(PcePath.class).encode(path, this));
   return ok(result.toString()).build();
 }
 /**
  * Convert a {@link ISelectableValueHolderCollection} into JSON.<br>
  * The structure is the following one : { "value" : {"value" : "the value", "name" : "the name",
  * "description" : "the description","url" : "the url"} }
  *
  * @param valueHoldersList a collection
  * @return a JSON object
  */
 public static <T> ObjectNode marshallAsJson(List<ISelectableValueHolder<T>> valueHoldersList) {
   ObjectNode valueHoldersAsJson = Json.newObject();
   if (valueHoldersList != null) {
     int order = 0;
     for (ISelectableValueHolder<T> valueHolder : valueHoldersList) {
       valueHoldersAsJson.set(
           String.valueOf(valueHolder.getValue()), marshallAsJson(valueHolder, order));
       order++;
     }
   }
   return valueHoldersAsJson;
 }
  @Override
  public ObjectNode encode(NextObjective nextObjective, CodecContext context) {

    checkNotNull(nextObjective, NOT_NULL_MESSAGE);

    final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
    final JsonCodec<TrafficSelector> trafficSelectorCodec = context.codec(TrafficSelector.class);

    // encode common properties
    ObjectiveCodecHelper och = new ObjectiveCodecHelper();
    ObjectNode result = och.encode(nextObjective, context);

    // encode id
    result.put(ID, nextObjective.id());

    // encode type
    result.put(TYPE, nextObjective.type().toString());

    // encode operation
    result.put(OPERATION, nextObjective.op().toString());

    // encode treatments
    ArrayNode treatments = context.mapper().createArrayNode();
    nextObjective
        .next()
        .forEach(
            t -> {
              ObjectNode treatmentJson = trafficTreatmentCodec.encode(t, context);
              treatments.add(treatmentJson);
            });
    result.set(TREATMENTS, treatments);

    // encode meta
    if (nextObjective.meta() != null) {
      ObjectNode trafficSelectorNode = trafficSelectorCodec.encode(nextObjective.meta(), context);
      result.set(META, trafficSelectorNode);
    }

    return result;
  }
Example #24
0
  private void processRestMethod(
      JavaMethod javaMethod,
      String method,
      Map<String, ObjectNode> pathMap,
      String resourcePath,
      ArrayNode tagArray) {
    String fullPath = resourcePath, consumes = "", produces = "", comment = javaMethod.getComment();
    for (JavaAnnotation annotation : javaMethod.getAnnotations()) {
      String name = annotation.getType().getName();
      if (name.equals(PATH)) {
        fullPath = resourcePath + "/" + getPath(annotation);
        fullPath = fullPath.replaceFirst("^//", "/");
      }
      if (name.equals(CONSUMES)) {
        consumes = getIOType(annotation);
      }
      if (name.equals(PRODUCES)) {
        produces = getIOType(annotation);
      }
    }
    ObjectNode methodNode = mapper.createObjectNode();
    methodNode.set("tags", tagArray);

    addSummaryDescriptions(methodNode, comment);
    processParameters(javaMethod, methodNode);

    processConsumesProduces(methodNode, "consumes", consumes);
    processConsumesProduces(methodNode, "produces", produces);

    addResponses(methodNode);

    ObjectNode operations = pathMap.get(fullPath);
    if (operations == null) {
      operations = mapper.createObjectNode();
      operations.set(method, methodNode);
      pathMap.put(fullPath, operations);
    } else {
      operations.set(method, methodNode);
    }
  }
Example #25
0
  /**
   * Get specified alarm. Returns details of the specified alarm.
   *
   * @param id ONOS allocated identifier
   * @return JSON encoded alarm
   */
  @GET
  @Path("{id}")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getAlarm(@PathParam("id") final String id) {
    log.info("HTTP GET alarm for id={}", id);

    final AlarmId alarmId = toAlarmId(id);
    final Alarm alarm = get(AlarmService.class).getAlarm(alarmId);

    final ObjectNode result = mapper().createObjectNode();
    result.set("alarm", codec(Alarm.class).encode(alarm, this));
    return ok(result.toString()).build();
  }
Example #26
0
  /**
   * Get all alarms. Returns a list of all alarms across all devices.
   *
   * @param includeCleared include recently cleared alarms in response
   * @return JSON encoded set of alarms
   */
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response getAlarms(
      @DefaultValue("false") @QueryParam("includeCleared") final boolean includeCleared) {

    log.info("Requesting all alarms, includeCleared={}", includeCleared);
    final AlarmService service = get(AlarmService.class);

    final Iterable<Alarm> alarms = includeCleared ? service.getAlarms() : service.getActiveAlarms();

    final ObjectNode result = new ObjectMapper().createObjectNode();
    result.set("alarms", codec(Alarm.class).encode(alarms, this));
    return ok(result.toString()).build();
  }
 public JsonNode getSchema(SerializerProvider paramSerializerProvider, Type paramType)
     throws JsonMappingException {
   ObjectNode localObjectNode1 = createSchemaNode("object", true);
   if ((paramType instanceof ParameterizedType)) {
     Object localObject = ((ParameterizedType) paramType).getActualTypeArguments();
     if (localObject.length == 2) {
       paramType = paramSerializerProvider.constructType(localObject[0]);
       localObject = paramSerializerProvider.constructType(localObject[1]);
       ObjectNode localObjectNode2 = JsonNodeFactory.instance.objectNode();
       Enum[] arrayOfEnum = (Enum[]) paramType.getRawClass().getEnumConstants();
       int j = arrayOfEnum.length;
       int i = 0;
       if (i < j) {
         Enum localEnum = arrayOfEnum[i];
         paramType =
             paramSerializerProvider.findValueSerializer(
                 ((JavaType) localObject).getRawClass(), this._property);
         if ((paramType instanceof SchemaAware)) {}
         for (paramType = ((SchemaAware) paramType).getSchema(paramSerializerProvider, null);
             ;
             paramType = JsonSchema.getDefaultSchemaNode()) {
           localObjectNode2.set(
               paramSerializerProvider
                   .getConfig()
                   .getAnnotationIntrospector()
                   .findEnumValue(localEnum),
               paramType);
           i += 1;
           break;
         }
       }
       localObjectNode1.set("properties", localObjectNode2);
     }
   }
   return localObjectNode1;
 }
 // Override needed to support legacy JSON Schema generator
 @Override
 protected void _depositSchemaProperty(ObjectNode propertiesNode, JsonNode schemaNode) {
   JsonNode props = schemaNode.get("properties");
   if (props != null) {
     Iterator<Entry<String, JsonNode>> it = props.fields();
     while (it.hasNext()) {
       Entry<String, JsonNode> entry = it.next();
       String name = entry.getKey();
       if (_nameTransformer != null) {
         name = _nameTransformer.transform(name);
       }
       propertiesNode.set(name, entry.getValue());
     }
   }
 }
  @RequestMapping("/drug/recalls")
  @ResponseBody
  public JsonNode getDrugRecalls(
      @RequestParam(value = "limit", defaultValue = "5") int limit,
      @RequestParam(value = "fromDt", defaultValue = "") String fromDt,
      @RequestParam(value = "toDt", defaultValue = "") String toDt)
      throws Exception {
    JsonNode node;
    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
    UriComponentsBuilder builder =
        UriComponentsBuilder.fromHttpUrl(searchDrugEnfrcmntUrl)
            .queryParam("search", getDefaultReportDateQuery(fromDt, toDt))
            .queryParam("limit", mostRecentRecallsLimit);
    this.apiKey.addToUriComponentsBuilder(builder);
    ObjectMapper mapper = new ObjectMapper();
    String json = rest.getForObject(builder.build().toUri(), String.class);
    node = mapper.readTree(json);
    ((ObjectNode) node).set("results", getSortedResults(node.get("results"), limit));

    return node;
  }
 @Override
 public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
   ObjectNode o = createSchemaNode("array", true);
   ObjectNode itemSchema = createSchemaNode("string"); // binary values written as strings?
   return o.set("items", itemSchema);
 }