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
!
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.
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);
}
}
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With