由于某种原因,杰克逊 2.3.0 无法解析 JSONP 响应。
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'my_json_callback':
我已经让反序列化过程在没有回调的情况下工作。
我已经尝试过使用包含@JSONP
注释的杰克逊 JAX-RS 包,但这似乎仅在序列化时使用。
使用ReaderInterceptor
提出的解决方案的修剪空间版本。我正在将Jersey 2.x与Jackson结合使用,以与仅输出JSONP的Web服务进行交互。
public class CallbackStripInterceptor implements ReaderInterceptor {
private final static byte[] callbackBytes = "callback(".getBytes();
@Override
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
int howMany = callbackBytes.length;
InputStream x = context.getInputStream();
if( !(x.available() >= howMany) ) {
return context.proceed();
}
x.mark( howMany );
byte[] preamble = new byte[ howMany ];
x.read( preamble );
// In case the first part of our entity doesn't have the callback String, reset the stream so downstream exploiters get the full entity.
if( !Arrays.equals( preamble, callbackBytes ) ) {
x.reset();
}
return context.proceed();
}
像这样使用:
Client c = ClientBuilder.newBuilder()
.register( new CallbackStripInterceptor() )
.build();
使用此客户端,具有实体的所有响应都将通过此侦听器(Jersey 不会在没有实体正文的响应上运行侦听器(。
我已经能够删除 JSONP 响应的回调部分。
首先,Jackson 能够解析 JSON,即使它以括号结尾。因此,只需从响应中删除my_json_callback(
就足够了。
由于我使用的是Apache的HTTP客户端,因此可以解决此问题:
String callback = "my_json_callback(";
InputStreamReader r = new InputStreamReader(response.getEntity().getContent());
r.skip(callback.length());
return mapper.readValue(r, MyObject.class);
这个想法是不必将读取器转换为字符串,然后在删除回调部分后解析该字符串。
我还能够使用给定 JSONP 字符串json.org
库中的JSONTokener
实现相同的结果:
JSONTokener t = new JSONTokener(json);
t.nextValue(); // skip the callback
return mapper.readValue(t.nextValue().toString(), MyObject.class);