Skip to content

Commit

Permalink
Preliminary work for #694 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Apr 4, 2021
1 parent a6c2976 commit 26f4d11
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 126 deletions.
202 changes: 79 additions & 123 deletions src/main/java/com/fasterxml/jackson/core/JsonLocation.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

package com.fasterxml.jackson.core;

import java.nio.charset.Charset;

import com.fasterxml.jackson.core.io.ContentReference;

/**
Expand All @@ -20,12 +18,9 @@ public class JsonLocation
private static final long serialVersionUID = 2L; // in 2.13

/**
* Include at most first 500 characters/bytes from contents; should be enough
* to give context, but not cause unfortunate side effects in things like
* logs.
*
* @since 2.9
* @deprecated Since 2.13 use {@link ContentReference#DEFAULT_MAX_CONTENT_SNIPPET} instead
*/
@Deprecated
public static final int MAX_CONTENT_SNIPPET = 500;

/**
Expand All @@ -52,6 +47,20 @@ public class JsonLocation
*/
protected final ContentReference _contentReference;

/**
* Lazily constructed description for source; constructed if and
* when {@link #sourceDescription()} is called, retained.
*
* @since 2.13
*/
protected transient String _sourceDescription;

/*
/**********************************************************************
/* Life cycle
/**********************************************************************
*/

public JsonLocation(ContentReference contentRef, long totalChars,
int lineNr, int colNr)
{
Expand All @@ -72,12 +81,12 @@ public JsonLocation(ContentReference contentRef, long totalBytes, long totalChar
_columnNr = columnNr;
}

@Deprecated
@Deprecated // since 2.13
public JsonLocation(Object srcRef, long totalChars, int lineNr, int columnNr) {
this(_wrap(srcRef), totalChars, lineNr, columnNr);
}

@Deprecated
@Deprecated // since 2.13
public JsonLocation(Object srcRef, long totalBytes, long totalChars,
int lineNr, int columnNr) {
this(_wrap(srcRef), totalBytes, totalChars, lineNr, columnNr);
Expand All @@ -90,6 +99,12 @@ protected static ContentReference _wrap(Object srcRef) {
return ContentReference.construct(false, srcRef);
}

/*
/**********************************************************************
/* Simple accessors
/**********************************************************************
*/

/**
* Accessor for information about the original input source content is being
* read from. Returned reference is never {@code null} but may not contain
Expand Down Expand Up @@ -124,49 +139,80 @@ public Object getSourceRef() {
}

/**
* @return Line number of the location (1-based)
* Access for getting line number of this location, if available.
* Note that line number is typically not available for binary formats.
*
* @return Line number of the location (1-based), if available; {@code -1} if not.
*/
public int getLineNr() { return _lineNr; }

/**
* @return Column number of the location (1-based)
* Access for getting column position of this location, if available.
* Note that column position is typically not available for binary formats.
*
* @return Column position of the location (1-based), if available; {@code -1} if not.
*/
public int getColumnNr() { return _columnNr; }

/**
* @return Character offset within underlying stream, reader or writer,
* if available; -1 if not.
* if available; {@code -1} if not.
*/
public long getCharOffset() { return _totalChars; }

/**
* @return Byte offset within underlying stream, reader or writer,
* if available; -1 if not.
* if available; {@code -1} if not.
*/
public long getByteOffset()
{
return _totalBytes;
}
public long getByteOffset() { return _totalBytes; }

/**
* Accessor for getting a textual description of source reference
* (Object returned by {@link #getSourceRef()}), as included in
* description returned by {@link #toString()}.
*<p>
* Note: implementation will simply call
* {@link ContentReference#buildSourceDescription()})
*<p>
* NOTE: not added as a "getter" to prevent it from getting serialized.
*
* @return Description of the source reference (see {@link #getSourceRef()}
*
* @since 2.9
*/
public String sourceDescription() {
return _appendSourceDesc(new StringBuilder(100)).toString();
// 04-Apr-2021, tatu: Construct lazily but retain
if (_sourceDescription == null) {
_sourceDescription = _contentReference.buildSourceDescription();
}
return _sourceDescription;
}

/**
* Accessor for a brief summary of Location offsets (line number, column position,
* or byte offset, if available).
*
* @return Description of available relevant location offsets; combination of
* line number and column position or byte offset
*
* @since 2.13
*/
public String offsetDescription() {
return appendOffsetDescription(new StringBuilder(40)).toString();
}

public StringBuilder appendOffsetDescription(StringBuilder sb) {
sb.append("line: ");
sb.append(_lineNr);
sb.append(", column: ");
sb.append(_columnNr);
return sb;
}

/*
/**********************************************************
/* Std method overrides
/**********************************************************
/**********************************************************************
/* Standard method overrides
/**********************************************************************
*/

@Override
Expand All @@ -190,117 +236,27 @@ public boolean equals(Object other)

if (_contentReference == null) {
if (otherLoc._contentReference != null) return false;
} else if (!_contentReference.equals(otherLoc._contentReference)) return false;
} else if (!_contentReference.equals(otherLoc._contentReference)) {
return false;
}

return (_lineNr == otherLoc._lineNr)
&& (_columnNr == otherLoc._columnNr)
&& (_totalChars == otherLoc._totalChars)
&& (getByteOffset() == otherLoc.getByteOffset())
&& (_totalBytes == otherLoc._totalBytes)
;
}

@Override
public String toString()
{
StringBuilder sb = new StringBuilder(80);
sb.append("[Source: ");
_appendSourceDesc(sb);
sb.append("; line: ");
sb.append(_lineNr);
sb.append(", column: ");
sb.append(_columnNr);
sb.append(']');
return sb.toString();
}

protected StringBuilder _appendSourceDesc(StringBuilder sb)
{
final Object srcRef = _contentReference.getRawContent();

if (srcRef == null) {
sb.append("UNKNOWN");
return sb;
}
// First, figure out what name to use as source type
Class<?> srcType = (srcRef instanceof Class<?>) ?
((Class<?>) srcRef) : srcRef.getClass();
String tn = srcType.getName();
// standard JDK types without package
if (tn.startsWith("java.")) {
tn = srcType.getSimpleName();
} else if (srcRef instanceof byte[]) { // then some other special cases
tn = "byte[]";
} else if (srcRef instanceof char[]) {
tn = "char[]";
}
sb.append('(').append(tn).append(')');

// and then, include (part of) contents for selected types
// (never for binary-format data)
if (_contentReference.hasTextualContent()) {
// First, retrieve declared offset+length for content; handle
// negative markers (can't do more for general case)
int offset, length;
offset = _contentReference.contentOffset();
if (offset < 0) {
offset = 0;
length = 0;
} else {
length = Math.max(0, _contentReference.contentLength());
}

String unitStr = " chars";
String trimmed;

if (srcRef instanceof CharSequence) {
trimmed = _truncate((CharSequence) srcRef, offset, length);
} else if (srcRef instanceof char[]) {
trimmed = _truncate((char[]) srcRef, offset, length);
} else if (srcRef instanceof byte[]) {
trimmed = _truncate((byte[]) srcRef, offset, length);
unitStr = " bytes";
} else {
trimmed = null;
}
if (trimmed != null) {
_append(sb, trimmed);
final int truncLen = length - trimmed.length();
if (truncLen > 0) {
sb.append("[truncated ").append(truncLen).append(unitStr).append(']');
}
}
} else {
// What should we do with binary content?
}
return sb;
}

private String _truncate(CharSequence cs, int start, int length) {
final int fullLength = cs.length();
start = Math.min(start, fullLength);
length = Math.min(Math.min(length, fullLength - start),
MAX_CONTENT_SNIPPET);
return cs.subSequence(start, start+length).toString();
}

private String _truncate(char[] cs, int start, int length) {
final int fullLength = cs.length;
start = Math.min(start, fullLength);
length = Math.min(Math.min(length, fullLength - start),
MAX_CONTENT_SNIPPET);
return new String(cs, start, length);
}

private String _truncate(byte[] b, int start, int length) {
final int fullLength = b.length;
start = Math.min(start, fullLength);
length = Math.min(Math.min(length, fullLength - start),
MAX_CONTENT_SNIPPET);
return new String(b, start, length, Charset.forName("UTF-8"));
}

private int _append(StringBuilder sb, String content) {
sb.append('"').append(content).append('"');
return content.length();
final String srcDesc = sourceDescription();
StringBuilder sb = new StringBuilder(40 + srcDesc.length())
.append("[Source: ")
.append(srcDesc)
.append("; ");
return appendOffsetDescription(sb)
.append(']')
.toString();
}
}
Loading

0 comments on commit 26f4d11

Please sign in to comment.