Convert InputStream into JSON
Asked Answered
B

4

30

I am using json-rpc-1.0.jar.Below is my code. I need to convert InputStream object into JSON since the response is in JSON.

I did verify the json response obtained from Zappos API. It is valid.

PrintWriter out = resp.getWriter();
String jsonString = null;
URL url = new URL("http://api.zappos.com/Search?term=boots&key=my_key");
InputStream inputStream = url.openConnection().getInputStream();
resp.setContentType("application/json");

JSONSerializer jsonSerializer = new JSONSerializer();
try {
   jsonString = jsonSerializer.toJSON(inputStream);
} catch (MarshallException e) {
 e.printStackTrace();
    }
out.print(jsonString);

I get the below mentioned exception:

com.metaparadigm.jsonrpc.MarshallException: can't marshall sun.net.www.protocol.http.HttpURLConnection$HttpInputStream
    at com.metaparadigm.jsonrpc.JSONSerializer.marshall(JSONSerializer.java:251)
    at com.metaparadigm.jsonrpc.JSONSerializer.toJSON(JSONSerializer.java:259)
    at Communicator.doGet(Communicator.java:33)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
    at filters.ExampleFilter.doFilter(ExampleFilter.java:149)
Bright answered 13/9, 2013 at 20:8 Comment(3)
First of all, setContentType() should be called before you send the request, ie. before getInputStream().Uriah
And post your full stack trace.Uriah
Might be better to convert InputStream to Stream<JsonNode>. #36048407Bevus
B
84

Make use of Jackson JSON parser.

Refer - Jackson Home

The only thing you need to do -

ObjectMapper mapper = new ObjectMapper();
Map<String, Object> jsonMap = mapper.readValue(inputStream, Map.class);

Now jsonMap will contain the JSON.

Bedchamber answered 13/9, 2013 at 20:49 Comment(4)
Ok. Looks like the Jackson Home page you asked to refer to, is OLD Jackson Java JSON-processor Home Page. I have downloaded jackson-core-2.2.3.jar. It does not seem to have ObjectMapper Class.Bright
Yes..They have shifted to fasterxml.com. BTW you need to download Core, Annotation & Databind jars.Bedchamber
Compilation error is : Bad class file ..ObjectMapper.class. Class file has wrong version 50.0,should be 48.0.Tomcat server is running java version 1.4.2_13. I have two options now. 1.Change java version on Tomcat. 2. Look for any other compatible json library. Which one should I go for. Its really a small application.Bright
I think you should change JAVA version, 1.4 is really too old, and I think you should update it.And as far as my opinion is concerned, Jackson is better that all the others.Bedchamber
D
6

ObjectMapper.readTree(InputStream) easily let's you get nested JSON with JsonNodes.

public void testMakeCall() throws IOException {
    URL url = new URL("https://api.coindesk.com/v1/bpi/historical/close.json?start=2010-07-17&end=2018-07-03");
    HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
    httpcon.addRequestProperty("User-Agent", "Mozilla/4.0");
    InputStream is = httpcon.getInputStream();

    try {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonMap = mapper.readTree(is);
        JsonNode bpi = jsonMap.get("bpi");
        JsonNode day1 = bpi.get("2010-07-18");

        System.out.println(bpi.toString());
        System.out.println(day1.toString());
    } finally {
        is.close();
    }
}

Result:

{"2010-07-18":0.0858,"2010-07-19":0.0808,...}

0.0858

Device answered 4/7, 2018 at 3:49 Comment(0)
B
1

Better to save memory by having output as Stream<JsonNode>


    private fun InputStream.toJsonNodeStream(): Stream<JsonNode> {
        return StreamSupport.stream(
                Spliterators.spliteratorUnknownSize(this.toJsonNodeIterator(), Spliterator.ORDERED),
                false
        )
    }

    private fun InputStream.toJsonNodeIterator(): Iterator<JsonNode> {
        val jsonParser = objectMapper.factory.createParser(this)

        return object: Iterator<JsonNode> {

            override fun hasNext(): Boolean {
                var token = jsonParser.nextToken()
                while (token != null) {
                    if (token == JsonToken.START_OBJECT) {
                        return true
                    }
                    token = jsonParser.nextToken()
                }
                return false
            }

            override fun next(): JsonNode {
                return jsonParser.readValueAsTree()
            }
        }
    }

Bevus answered 24/11, 2019 at 0:19 Comment(4)
what library is this?Linell
What language is this?Diploma
@Diploma this is kotlinYeld
@Linell it is Jackson databind libraryYeld
R
0

Below is a working solution in Java 8 for handling an empty Stream when converting it to a JSON String: Sometimes if the Stream is empty and you are trying to convert the empty stream to JSON String then you may face the below issue

No content to map due to end-of-input
 at [Source: (com.ibm.ws.webcontainer31.srt.SRTInputStream31); line: 1, column: 0]
com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (com.ibm.ws.webcontainer31.srt.SRTInputStream31); line: 1, column: 0]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)

Hence, handle the Stream to JSON string conversion with the following steps:

  1. Convert Stream to String as mentioned below:
InputStream entityStream = requestContext.getEntityStream();
String requestString = new BufferedReader(new InputStreamReader(entityStream, StandardCharsets.UTF_8))
                       .lines().collect(Collectors.joining());

Since the intention is to convert the InputStream directly to a JSON string, and assuming the content-type is "application/json," using the objectMapper may not be necessary.

However, in case you need to format the JSON string, you can use the following code snippets to format the JSON string into a pretty printed format:

ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(request);
String formattedStringRequest = StringUtils.isBlank(request) ? null : 
                    objectMapper.writeValueAsString(jsonNode);

For other types of conversions, such as mapping to a custom class:

CustomClass customClass = StringUtils.isBlank(requestString) ? null :
                    objectMapper.readValue(requestString, CustomClass.class);

These steps should help you handle the Stream to JSON string conversion and handle any potential issues related to empty Streams.

Rhodian answered 1/4 at 4:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.