Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
262 views
in Technique[技术] by (71.8m points)

java - How to extract part of the *original* text from JSON with Jackson?

PLEASE, don't edit the question for me. My question is on String manipulation, changing the flow of text can very likely change the meaning of the question and cause confusion.

The problem can be viewed as a String manipulation problem. But I expect a solution in Jackson to solve my problem.


Suppose I have received a String {"payload":{"foo":"bar","ipsum":["lorem","lorem"]},"signature":"somehmacsign"}. When it's displayed, it's like:

{
    "payload": {
        "foo": "bar",
        "ipsum": [
            "lorem",
            "lorem"
        ]
    },
    "signature": "somehmacsign"
}

How can I extract its substring from 11th character { till the } just before ,"signature". Namely, {"foo":"bar","ipsum":["lorem","lorem"]}. Semantically, I want to extract the original string representation for the payload field. I suppose it should not involve parsing the JSON string to Java objects and back to String. I don't want to risk losing the order of fields, spacing, or whatever small features because it's meant to be HMAC signed.


EDIT 1: Rephrased to clarify that this problem has nothing to do with Java String literal.

EDIT 2: Though it may be a bit early to say, there is no obvious off-the-shelf solution to my question in general (how to partial extract/parse a JSON string). In fact, I myself find my lazy/partial parsing theory a bit verbose. It requires way too many of passes to locate a deeply-nested node.

In particular for my situation, I found appending the signature in the body of a request a bad idea as it poses difficulties for the receiving party. I'm considering moving the signature to HTTP header, maybe X-Auth-Token?

EDIT 3: As it turns out, I was really concluding too early. Cassio's answer perfectly solves the problem by using custom deserializer and the magic skipChildren!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You could move the signature to a HTTP header to make things simpler.

However, if you want to keep the signature in the request payload, follow the steps described below.

Creating a custom deserializer

Create a custom deserializer that can get the raw JSON string value:

public class RawJsonDeserializer extends JsonDeserializer<String> {

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt)
           throws IOException, JsonProcessingException {

        long begin = jp.getCurrentLocation().getCharOffset();
        jp.skipChildren();
        long end = jp.getCurrentLocation().getCharOffset();

        String json = jp.getCurrentLocation().getSourceRef().toString();
        return json.substring((int) begin - 1, (int) end);
    }
}

Creating a Java class to hold the values

Create a Java class to hold the values (pay attention to the @JsonDeserialize annotation):

public class Request {

    @JsonDeserialize(using = RawJsonDeserializer.class)
    private String payload;

    private String signature;

    // Getters and setters ommitted
}

Parsing the JSON

Parse the JSON using ObjectMapper and Jackson will use the deserializer you have defined above:

String json = "{"payload":{"foo":"bar","ipsum":["lorem"," +
              ""lorem"]},"signature":"somehmacsign"}";

ObjectMapper mapper = new ObjectMapper();
Request request = mapper.readValue(json, Request.class);

If the payload is an invalid JSON, Jackson will throw an exception.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...