Skip to content

Commit

Permalink
Second part of #668 refactoring (#1301)
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder authored Jun 11, 2024
1 parent a2baece commit 99b0025
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 32 deletions.
195 changes: 191 additions & 4 deletions src/main/java/tools/jackson/core/JacksonException.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
package tools.jackson.core;

import java.io.Closeable;
import java.io.Serializable;
import java.util.Collection;
import java.util.Objects;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
* Base class for all Jackson-produced checked exceptions.
*<p>
* Note that in Jackson 2.x this exception extended {@link java.io.IOException}
* but in 3.x {@link RuntimeException}
*/
public abstract class JacksonException
public class JacksonException
extends RuntimeException
{
private final static long serialVersionUID = 3L; // eclipse complains otherwise

/**
* Let's limit length of reference chain, to limit damage in cases
* of infinite recursion.
*/
private final static int MAX_REFS_TO_LIST = 1000;

/**
* Simple bean class used to contain references. References
* can be added to indicate execution/reference path that
Expand Down Expand Up @@ -151,6 +158,20 @@ Object writeReplace() {

protected JsonLocation _location;

/**
* Path through which problem that triggering throwing of
* this exception was reached.
*/
protected LinkedList<Reference> _path;

/**
* Underlying processor ({@link JsonParser} or {@link JsonGenerator}),
* if known.
*<p>
* NOTE: typically not serializable hence <code>transient</code>
*/
protected transient Closeable _processor;

/*
/**********************************************************************
/* Life-cycle
Expand Down Expand Up @@ -192,6 +213,149 @@ public JacksonException clearLocation() {
return this;
}

/*
/**********************************************************************
/* Life-cycle: more advanced factory-like methods
/**********************************************************************
*/

/**
* Method that can be called to either create a new DatabindException
* (if underlying exception is not a DatabindException), or augment
* given exception with given path/reference information.
*
* This version of method is called when the reference is through a
* non-indexed object, such as a Map or POJO/bean.
*/
public static JacksonException wrapWithPath(Throwable src, Object refFrom,
String refPropertyName) {
return wrapWithPath(src, new Reference(refFrom, refPropertyName));
}

/**
* Method that can be called to either create a new DatabindException
* (if underlying exception is not a DatabindException), or augment
* given exception with given path/reference information.
*
* This version of method is called when the reference is through an
* index, which happens with arrays and Collections.
*/
public static JacksonException wrapWithPath(Throwable src, Object refFrom, int index) {
return wrapWithPath(src, new Reference(refFrom, index));
}

/**
* Method that can be called to either create a new DatabindException
* (if underlying exception is not a DatabindException), or augment
* given exception with given path/reference information.
*/
@SuppressWarnings("resource")
public static JacksonException wrapWithPath(Throwable src, Reference ref)
{
JacksonException jme;
if (src instanceof JacksonException) {
jme = (JacksonException) src;
} else {
// [databind#2128]: try to avoid duplication
String msg = _exceptionMessage(src);
// Let's use a more meaningful placeholder if all we have is null
if (msg == null || msg.isEmpty()) {
msg = "(was "+src.getClass().getName()+")";
}
// 17-Aug-2015, tatu: Let's also pass the processor (parser/generator) along
Closeable proc = null;
if (src instanceof JacksonException) {
Object proc0 = ((JacksonException) src).processor();
if (proc0 instanceof Closeable) {
proc = (Closeable) proc0;
}
}
jme = new JacksonException(msg, src);
jme._processor = proc;
}
jme.prependPath(ref);
return jme;
}

private static String _exceptionMessage(Throwable t) {
if (t instanceof JacksonException) {
return ((JacksonException) t).getOriginalMessage();
}
if (t instanceof InvocationTargetException && t.getCause() != null) {
return t.getCause().getMessage();
}
return t.getMessage();
}

/*
/**********************************************************************
/* Life-cycle: information augmentation (cannot use factory style, alas)
/**********************************************************************
*/

/**
* Method called to prepend a reference information in front of
* current path
*/
public JacksonException prependPath(Object referrer, String propertyName) {
return prependPath(new Reference(referrer, propertyName));
}

/**
* Method called to prepend a reference information in front of
* current path
*/
public JacksonException prependPath(Object referrer, int index) {
return prependPath(new Reference(referrer, index));
}

public JacksonException prependPath(Reference r)
{
if (_path == null) {
_path = new LinkedList<Reference>();
}
// Also: let's not increase without bounds. Could choose either
// head or tail; tail is easier (no need to ever remove), as
// well as potentially more useful so let's use it:
if (_path.size() < MAX_REFS_TO_LIST) {
_path.addFirst(r);
}
return this;
}

/*
/**********************************************************************
/* Accessors
/**********************************************************************
*/

/**
* Method for accessing full structural path within type hierarchy
* down to problematic property.
*/
public List<Reference> getPath()
{
if (_path == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(_path);
}

/**
* Method for accessing description of path that lead to the
* problem that triggered this exception
*/
public String getPathReference()
{
return getPathReference(new StringBuilder()).toString();
}

public StringBuilder getPathReference(StringBuilder sb)
{
_appendPathDesc(sb);
return sb;
}

/*
/**********************************************************************
/* Extended API
Expand Down Expand Up @@ -238,7 +402,9 @@ public JacksonException clearLocation() {
*
* @return Originating processor, if available; {@code null} if not.
*/
public abstract Object processor();
public Object processor() {
return _processor;
}

/*
/**********************************************************************
Expand Down Expand Up @@ -297,4 +463,25 @@ public JacksonException clearLocation() {
}

@Override public String toString() { return getClass().getName()+": "+getMessage(); }

/*
/**********************************************************************
/* Internal methods
/**********************************************************************
*/

protected void _appendPathDesc(StringBuilder sb)
{
if (_path == null) {
return;
}
Iterator<Reference> it = _path.iterator();
while (it.hasNext()) {
sb.append(it.next().toString());
if (it.hasNext()) {
sb.append("->");
}
}
}

}
2 changes: 1 addition & 1 deletion src/main/java/tools/jackson/core/TokenStreamFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,7 @@ protected <T> T _reportRangeError(String msg) throws JacksonException
*/

protected JacksonException _wrapIOFailure(IOException e) {
return JacksonIOException.construct(e, this);
return JacksonIOException.construct(e, null);
}

protected <T> T _unsupported() {
Expand Down
16 changes: 4 additions & 12 deletions src/main/java/tools/jackson/core/exc/JacksonIOException.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tools.jackson.core.exc;

import java.io.Closeable;
import java.io.IOException;

import tools.jackson.core.JacksonException;
Expand All @@ -25,13 +26,7 @@ public class JacksonIOException extends JacksonException
{
private final static long serialVersionUID = 1L;

/**
* Optional processor, often of parser, generator type
* (or equivalent read/write context from databinding).
*/
protected transient Object _processor;

protected JacksonIOException(Object processor, IOException source) {
protected JacksonIOException(Closeable processor, IOException source) {
super(source.getMessage(), source);
_processor = processor;
}
Expand All @@ -40,18 +35,15 @@ public static JacksonIOException construct(IOException e) {
return construct(e, null);
}

public static JacksonIOException construct(IOException e, Object processor) {
public static JacksonIOException construct(IOException e, Closeable processor) {
return new JacksonIOException(processor, e);
}

public JacksonIOException withProcessor(Object processor) {
public JacksonIOException withProcessor(Closeable processor) {
_processor = processor;
return this;
}

@Override
public Object processor() { return _processor; }

@Override // just for co-variant type
public IOException getCause() {
return (IOException) super.getCause();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,4 @@ public StreamConstraintsException(String msg) {
public StreamConstraintsException(String msg, JsonLocation loc) {
super(msg, loc, null);
}

// !!! TODO? Allow setting parser/generator
@Override
public Object processor() { return null; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ public class StreamReadException
{
private final static long serialVersionUID = 3L;

protected transient JsonParser _processor;

public StreamReadException(String msg) {
super(msg);
_processor = null;
Expand All @@ -39,11 +37,6 @@ public StreamReadException(JsonParser p, String msg, JsonLocation loc,
_processor = p;
}

@Deprecated // @since 3.0 -- is this still in use?
protected StreamReadException(String msg, JsonLocation loc, Throwable rootCause) {
super(msg, loc, rootCause);
}

/**
* Fluent method that may be used to assign originating {@link JsonParser},
* to be accessed using {@link #processor()}.
Expand All @@ -61,6 +54,6 @@ public StreamReadException withParser(JsonParser p) {

@Override
public JsonParser processor() {
return _processor;
return (JsonParser) _processor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ public class StreamWriteException
{
private final static long serialVersionUID = 3L;

protected transient JsonGenerator _processor;

public StreamWriteException(JsonGenerator g, Throwable rootCause) {
super(rootCause);
_processor = g;
Expand Down Expand Up @@ -42,5 +40,5 @@ public StreamWriteException withGenerator(JsonGenerator g) {
}

@Override
public JsonGenerator processor() { return _processor; }
public JsonGenerator processor() { return (JsonGenerator) _processor; }
}

0 comments on commit 99b0025

Please sign in to comment.