Skip to content

Commit

Permalink
Additional streamlining for #86; need to ensure exception remains ser…
Browse files Browse the repository at this point in the history
…ializable
  • Loading branch information
cowtowncoder committed Apr 15, 2016
1 parent 2c33498 commit 6e3999e
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 177 deletions.
2 changes: 2 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ Lokesh Kumar N (LokeshN@github)
(2.7.4)
* Contributed fix for #117: Support for missing values (non-compliant JSON)
(2.8.0)
* Contributed implementation for #86: Allow inclusion of request body for JsonParseException
(2.8.0)

Mikael Staldal (mikaelstaldal@github)
* Contributed fix for #265: `JsonStringEncoder` should allow passing `CharSequence`
Expand Down
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ JSON library.

2.8.0 (not yet released)

#86: Allow inclusion of request body for JsonParseException
(contributed by LokeshN)
#117: Add `JsonParser.Feature.ALLOW_MISSING_VALUES` to support for missing values
(contributed by LokeshN)
#253: Add `JsonGenerator. writeEmbeddedObject()` to allow writes of opaque native types
Expand Down
90 changes: 38 additions & 52 deletions src/main/java/com/fasterxml/jackson/core/JsonParseException.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,7 @@

package com.fasterxml.jackson.core;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.CharBuffer;
import java.nio.charset.Charset;

import com.fasterxml.jackson.core.util.RequestPayloadWrapper;
import com.fasterxml.jackson.core.util.RequestPayload;

/**
* Exception type for parsing problems, used when non-well-formed content
Expand All @@ -24,7 +16,7 @@ public class JsonParseException extends JsonProcessingException {
private static final long serialVersionUID = 2L; // 2.7

protected JsonParser _processor;
protected RequestPayloadWrapper requestPayload;
protected RequestPayload _requestPayload;

@Deprecated // since 2.7
public JsonParseException(String msg, JsonLocation loc) {
Expand Down Expand Up @@ -71,35 +63,12 @@ public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable
super(msg, loc, root);
_processor = p;
}

/*
*******************************************************************
Extended Constructors for setting the Request Body in the exception
*******************************************************************
*/
public JsonParseException(JsonParser p, String msg, RequestPayloadWrapper requestPayload) {
this(p, msg);
this.requestPayload = requestPayload;
}

public JsonParseException(JsonParser p, String msg, Throwable root, RequestPayloadWrapper requestPayload) {
this(p, msg, root);
this.requestPayload = requestPayload;
}

public JsonParseException(JsonParser p, String msg, JsonLocation loc, RequestPayloadWrapper requestPayload) {
this(p, msg, loc);
this.requestPayload = requestPayload;
}

public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable root, RequestPayloadWrapper requestPayload) {
this(p, msg, loc, root);
this.requestPayload = requestPayload;
}

/**
* Fluent method that may be used to assign originating {@link JsonParser},
* to be accessed using {@link #getProcessor()}.
*<p>
* NOTE: `this` instance is modified and no new instance is constructed.
*
* @since 2.7
*/
Expand All @@ -108,40 +77,57 @@ public JsonParseException withParser(JsonParser p) {
return this;
}

/**
* Fluent method that may be used to assign payload to this exception,
* to let recipient access it for diagnostics purposes.
*<p>
* NOTE: `this` instance is modified and no new instance is constructed.
*
* @since 2.8
*/
public JsonParseException withRequestPayload(RequestPayload p) {
_requestPayload = p;
return this;
}

@Override
public JsonParser getProcessor() {
return _processor;
}

/**
* Method to get the raw request payload
* The raw payload will be in either byte[] or String
*
* @return raw request payload object either in bytes or in string
* Method that may be called to find payload that was being parsed, if
* one was specified for parser that threw this Exception.
*
* @return request body, if payload was specified; `null` otherwise
*
* @since 2.8
*/
public Object getRawRequestPayload() {
return requestPayload != null ? requestPayload.getRawRequestPayload() : null;
public RequestPayload getRequestPayload() {
return _requestPayload;
}

/**
* The method returns the String representation of the request payload
* The raw request payload could be in String or in byte[], the method
* returns the raw request payload in String format
* The method returns the String representation of the request payload if
* one was specified for parser that threw this Exception.
*
* @return request body as String
* @return request body as String, if payload was specified; `null` otherwise
*
* @since 2.8
*/
public String getRequestPayload() {
return requestPayload != null ? requestPayload.toString() : null;
public String getRequestPayloadAsString() {
return (_requestPayload != null) ? _requestPayload.toString() : null;
}

/**
* Overriding the getMessage() to include the request body
*/
@Override
public String getMessage() {
String msg = super.getMessage();
return requestPayload != null ? (msg + "\nRequest Payload : " + getRequestPayload()) : msg;
String msg = super.getMessage();
if (_requestPayload != null) {
msg += "\nRequest payload : " + _requestPayload.toString();
}
return msg;
}


}
62 changes: 36 additions & 26 deletions src/main/java/com/fasterxml/jackson/core/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import java.util.Iterator;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.util.RequestPayloadWrapper;
import com.fasterxml.jackson.core.util.RequestPayload;

/**
* Base class that defines public API for reading JSON content.
Expand Down Expand Up @@ -281,30 +281,11 @@ private Feature(boolean defaultState) {
protected int _features;

/**
* Wrapper object holding the request payload which will be displayed on json parsing error
*/
protected RequestPayloadWrapper requestPayloadWrapper;

/**
* Sets the byte[] request payload and the charset
*
* @param requestPayloadOnError
* @param charset
*/
public void setRequestPayloadOnError(byte[] requestPayloadOnError, String charset) {
this.requestPayloadWrapper = new RequestPayloadWrapper(requestPayloadOnError, charset);
}

/**
* Sets the String request payload
* Optional container that holds the request payload which will be displayed on JSON parsing error.
*
* @param requestPayloadOnError
* @param charset
* @since 2.8
*/
public void setRequestPayloadOnError(String requestPayloadOnError) {
this.requestPayloadWrapper = new RequestPayloadWrapper(requestPayloadOnError);
}

protected transient RequestPayload _requestPayload;

/*
/**********************************************************
Expand Down Expand Up @@ -378,13 +359,40 @@ public void setCurrentValue(Object v) {
ctxt.setCurrentValue(v);
}
}

/**
* Sets the payload to be passed if {@link JsonParseException} is thrown.
*
* @since 2.8
*/
public void setRequestPayloadOnError(RequestPayload payload) {
_requestPayload = payload;
}

/**
* Sets the byte[] request payload and the charset
*
* @since 2.8
*/
public void setRequestPayloadOnError(byte[] payload, String charset) {
_requestPayload = (payload == null) ? null : new RequestPayload(payload, charset);
}

/**
* Sets the String request payload
*
* @since 2.8
*/
public void setRequestPayloadOnError(String payload) {
_requestPayload = (payload == null) ? null : new RequestPayload(payload);
}

/*
/**********************************************************
/* Format support
/**********************************************************
*/

/**
* Method to call to make this parser use specified schema. Method must
* be called before trying to parse any content, right after parser instance
Expand Down Expand Up @@ -1240,7 +1248,8 @@ public boolean getBooleanValue() throws IOException {
if (t == JsonToken.VALUE_TRUE) return true;
if (t == JsonToken.VALUE_FALSE) return false;
throw new JsonParseException(this,
String.format("Current token (%s) not of boolean type", t), requestPayloadWrapper);
String.format("Current token (%s) not of boolean type", t))
.withRequestPayload(_requestPayload);
}

/**
Expand Down Expand Up @@ -1646,7 +1655,8 @@ protected ObjectCodec _codec() {
* based on current state of the parser
*/
protected JsonParseException _constructError(String msg) {
return new JsonParseException(this, msg, requestPayloadWrapper);
return new JsonParseException(this, msg)
.withRequestPayload(_requestPayload);
}

/**
Expand Down
67 changes: 67 additions & 0 deletions src/main/java/com/fasterxml/jackson/core/util/RequestPayload.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.fasterxml.jackson.core.util;

import java.io.IOException;

/**
* Container object used to contain optional information on content
* being parsed, passed to {@link com.fasterxml.jackson.core.JsonParseException} in case of
* exception being thrown; this may be useful for caller to display
* information on failure.
*
* @since 2.8
*/
public class RequestPayload
implements java.io.Serializable // just in case, even though likely included as transient
{
private static final long serialVersionUID = 1L;

// request payload as byte[]
protected byte[] _payloadAsBytes;

// request payload as String
protected CharSequence _payloadAsText;

// Charset if the request payload is set in bytes
protected String _charset;

public RequestPayload(byte[] bytes, String charset) {
if (bytes == null) {
throw new IllegalArgumentException();
}
_payloadAsBytes = bytes;
_charset = (charset == null || charset.isEmpty()) ? "UTF-8" : charset;
}

public RequestPayload(CharSequence str) {
if (str == null) {
throw new IllegalArgumentException();
}
_payloadAsText = str;
}

/**
* Returns the raw request payload object i.e, either byte[] or String
*
* @return Object which is a raw request payload i.e, either byte[] or
* String
*/
public Object getRawPayload() {
if (_payloadAsBytes != null) {
return _payloadAsBytes;
}

return _payloadAsText;
}

@Override
public String toString() {
if (_payloadAsBytes != null) {
try {
return new String(_payloadAsBytes, _charset);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return _payloadAsText.toString();
}
}
Loading

0 comments on commit 6e3999e

Please sign in to comment.