Skip to content

Commit f93f883

Browse files
committed
Fix #668: move Reference to JacksonException
1 parent 6eb2766 commit f93f883

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ JSON library.
2727
#492: Ensure primitive type names in error message enclosed in backticks
2828
#551: Remove `JsonGenerator.setPrettyPrinter()` from 3.0
2929
#663: Rename `JsonEOFException` as `UnexpectedEndOfInputException`
30+
#668: Add `JacksonException.Reference` (demote from `JsonMappingException`/`DatabindException`)
3031
#670: Replace references to "field" with "property" in `JsonGenerator`, `JsonParser`, method names;
3132
`JsonToken` values (`JsonToken.FIELD_NAME` -> `JsonToken.PROPERTY_NAME`)
3233
#671: Replace `getCurrentLocation()`/`getTokenLocation()` with

src/main/java/tools/jackson/core/JacksonException.java

+138
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package tools.jackson.core;
22

3+
import java.io.Serializable;
4+
import java.util.Collection;
5+
import java.util.Objects;
6+
37
/**
48
* Base class for all Jackson-produced checked exceptions.
59
*<p>
@@ -11,6 +15,140 @@ public abstract class JacksonException
1115
{
1216
private final static long serialVersionUID = 3L; // eclipse complains otherwise
1317

18+
/**
19+
* Simple bean class used to contain references. References
20+
* can be added to indicate execution/reference path that
21+
* lead to the problem that caused this exception to be
22+
* thrown.
23+
*
24+
* @since 3.0 (in 2.x was part of databind-level exceptions only)
25+
*/
26+
public static class Reference implements Serializable
27+
{
28+
private static final long serialVersionUID = 3L;
29+
30+
protected transient Object _from;
31+
32+
/**
33+
* Name of property (for POJO) or key (for Maps) that is part
34+
* of the reference. May be null for Collection types (which
35+
* generally have {@link #_index} defined), or when resolving
36+
* Map classes without (yet) having an instance to operate on.
37+
*/
38+
protected String _propertyName;
39+
40+
/**
41+
* Index within a {@link Collection} instance that contained
42+
* the reference; used if index is relevant and available.
43+
* If either not applicable, or not available, -1 is used to
44+
* denote "not known" (or not relevant).
45+
*/
46+
protected int _index = -1;
47+
48+
/**
49+
* Lazily-constructed description of this instance; needed mostly to
50+
* allow JDK serialization to work in case where {@link #_from} is
51+
* non-serializable (and has to be dropped) but we still want to pass
52+
* actual description along.
53+
*/
54+
protected String _desc;
55+
56+
/**
57+
* Default constructor for deserialization purposes
58+
*/
59+
protected Reference() { }
60+
61+
public Reference(Object from) { _from = from; }
62+
63+
public Reference(Object from, String propertyName) {
64+
_from = from;
65+
_propertyName = Objects.requireNonNull(propertyName, "Cannot pass null 'propertyName'");
66+
}
67+
68+
public Reference(Object from, int index) {
69+
_from = from;
70+
_index = index;
71+
}
72+
73+
// Setters to let Jackson deserialize instances, but not to be called from outside
74+
void setPropertyName(String n) { _propertyName = n; }
75+
void setIndex(int ix) { _index = ix; }
76+
void setDescription(String d) { _desc = d; }
77+
78+
/**
79+
* Object through which reference was resolved. Can be either
80+
* actual instance (usually the case for serialization), or
81+
* Class (usually the case for deserialization).
82+
*<p>
83+
* Note that this the accessor is not a getter on purpose as we cannot
84+
* (in general) serialize/deserialize this reference
85+
*/
86+
public Object from() { return _from; }
87+
88+
public String getPropertyName() { return _propertyName; }
89+
public int getIndex() { return _index; }
90+
91+
public String getDescription()
92+
{
93+
if (_desc == null) {
94+
StringBuilder sb = new StringBuilder();
95+
96+
if (_from == null) { // can this ever occur?
97+
sb.append("UNKNOWN");
98+
} else {
99+
Class<?> cls = (_from instanceof Class<?>) ? (Class<?>)_from : _from.getClass();
100+
// Hmmh. Although Class.getName() is mostly ok, it does look
101+
// butt-ugly for arrays.
102+
// 06-Oct-2016, tatu: as per [databind#1403], `getSimpleName()` not so good
103+
// as it drops enclosing class. So let's try bit different approach
104+
int arrays = 0;
105+
while (cls.isArray()) {
106+
cls = cls.getComponentType();
107+
++arrays;
108+
}
109+
sb.append(cls.getName());
110+
while (--arrays >= 0) {
111+
sb.append("[]");
112+
}
113+
}
114+
sb.append('[');
115+
if (_propertyName != null) {
116+
sb.append('"');
117+
sb.append(_propertyName);
118+
sb.append('"');
119+
} else if (_index >= 0) {
120+
sb.append(_index);
121+
} else {
122+
sb.append('?');
123+
}
124+
sb.append(']');
125+
_desc = sb.toString();
126+
}
127+
return _desc;
128+
}
129+
130+
@Override
131+
public String toString() {
132+
return getDescription();
133+
}
134+
135+
/**
136+
* May need some cleaning here, given that `from` may or may not be serializable.
137+
*/
138+
Object writeReplace() {
139+
// as per [databind#1195], need to ensure description is not null, since
140+
// `_from` is transient
141+
getDescription();
142+
return this;
143+
}
144+
}
145+
146+
/*
147+
/**********************************************************************
148+
/* State/configuration
149+
/**********************************************************************
150+
*/
151+
14152
protected JsonLocation _location;
15153

16154
/*

0 commit comments

Comments
 (0)