1
5
6 package com.fasterxml.jackson.core;
7
8 import java.nio.charset.Charset;
9
10
15 public class JsonLocation
16 implements java.io.Serializable
17 {
18 private static final long serialVersionUID = 1L;
19
20
27 public static final int MAX_CONTENT_SNIPPET = 500;
28
29
36 public final static JsonLocation NA = new JsonLocation(null, -1L, -1L, -1, -1);
37
38 protected final long _totalBytes;
39 protected final long _totalChars;
40
41 protected final int _lineNr;
42 protected final int _columnNr;
43
44
49 final transient Object _sourceRef;
50
51 public JsonLocation(Object srcRef, long totalChars, int lineNr, int colNr)
52 {
53
58 this(srcRef, -1L, totalChars, lineNr, colNr);
59 }
60
61 public JsonLocation(Object sourceRef, long totalBytes, long totalChars,
62 int lineNr, int columnNr)
63 {
64 _sourceRef = sourceRef;
65 _totalBytes = totalBytes;
66 _totalChars = totalChars;
67 _lineNr = lineNr;
68 _columnNr = columnNr;
69 }
70
71
79 public Object getSourceRef() { return _sourceRef; }
80
81
84 public int getLineNr() { return _lineNr; }
85
86
89 public int getColumnNr() { return _columnNr; }
90
91
95 public long getCharOffset() { return _totalChars; }
96
97
101 public long getByteOffset()
102 {
103 return _totalBytes;
104 }
105
106
115 public String sourceDescription() {
116 return _appendSourceDesc(new StringBuilder(100)).toString();
117 }
118
119
124
125 @Override
126 public int hashCode()
127 {
128 int hash = (_sourceRef == null) ? 1 : _sourceRef.hashCode();
129 hash ^= _lineNr;
130 hash += _columnNr;
131 hash ^= (int) _totalChars;
132 hash += (int) _totalBytes;
133 return hash;
134 }
135
136 @Override
137 public boolean equals(Object other)
138 {
139 if (other == this) return true;
140 if (other == null) return false;
141 if (!(other instanceof JsonLocation)) return false;
142 JsonLocation otherLoc = (JsonLocation) other;
143
144 if (_sourceRef == null) {
145 if (otherLoc._sourceRef != null) return false;
146 } else if (!_sourceRef.equals(otherLoc._sourceRef)) return false;
147
148 return (_lineNr == otherLoc._lineNr)
149 && (_columnNr == otherLoc._columnNr)
150 && (_totalChars == otherLoc._totalChars)
151 && (getByteOffset() == otherLoc.getByteOffset())
152 ;
153 }
154
155 @Override
156 public String toString()
157 {
158 StringBuilder sb = new StringBuilder(80);
159 sb.append("[Source: ");
160 _appendSourceDesc(sb);
161 sb.append("; line: ");
162 sb.append(_lineNr);
163 sb.append(", column: ");
164 sb.append(_columnNr);
165 sb.append(']');
166 return sb.toString();
167 }
168
169 protected StringBuilder _appendSourceDesc(StringBuilder sb)
170 {
171 final Object srcRef = _sourceRef;
172
173 if (srcRef == null) {
174 sb.append("UNKNOWN");
175 return sb;
176 }
177
178 Class<?> srcType = (srcRef instanceof Class<?>) ?
179 ((Class<?>) srcRef) : srcRef.getClass();
180 String tn = srcType.getName();
181
182 if (tn.startsWith("java.")) {
183 tn = srcType.getSimpleName();
184 } else if (srcRef instanceof byte[]) {
185 tn = "byte[]";
186 } else if (srcRef instanceof char[]) {
187 tn = "char[]";
188 }
189 sb.append('(').append(tn).append(')');
190
191 int len;
192 String charStr = " chars";
193
194 if (srcRef instanceof CharSequence) {
195 CharSequence cs = (CharSequence) srcRef;
196 len = cs.length();
197 len -= _append(sb, cs.subSequence(0, Math.min(len, MAX_CONTENT_SNIPPET)).toString());
198 } else if (srcRef instanceof char[]) {
199 char[] ch = (char[]) srcRef;
200 len = ch.length;
201 len -= _append(sb, new String(ch, 0, Math.min(len, MAX_CONTENT_SNIPPET)));
202 } else if (srcRef instanceof byte[]) {
203 byte[] b = (byte[]) srcRef;
204 int maxLen = Math.min(b.length, MAX_CONTENT_SNIPPET);
205 _append(sb, new String(b, 0, maxLen, Charset.forName("UTF-8")));
206 len = b.length - maxLen;
207 charStr = " bytes";
208 } else {
209 len = 0;
210 }
211 if (len > 0) {
212 sb.append("[truncated ").append(len).append(charStr).append(']');
213 }
214 return sb;
215 }
216
217 private int _append(StringBuilder sb, String content) {
218 sb.append('"').append(content).append('"');
219 return content.length();
220 }
221 }
222