CollectedProblem.java
package tools.jackson.databind.exc;
import java.util.Objects;
import tools.jackson.core.JsonPointer;
import tools.jackson.core.JsonToken;
import tools.jackson.core.TokenStreamLocation;
import tools.jackson.databind.JavaType;
/**
* Immutable value object capturing details about a single deserialization
* problem encountered during error-collecting mode.
*
* <p><b>Contents</b>: Each problem records:
* <ul>
* <li>{@link #getPath() path} - RFC 6901 JSON Pointer to the problematic field
* (e.g., {@code "/items/2/price"})</li>
* <li>{@link #getMessage() message} - Human-readable error description</li>
* <li>{@link #getTargetType() targetType} - Expected Java type (may be null)</li>
* <li>{@link #getLocation() location} - Source location in JSON (line/column)</li>
* <li>{@link #getRawValue() rawValue} - Original value from JSON that caused the error
* (truncated if > 200 chars)</li>
* <li>{@link #getToken() token} - JSON token type at error location</li>
* </ul>
*
* <p><b>Truncation</b>: String values longer than {@code #MAX_RAW_VALUE_LENGTH}
* (currently: 200)
* characters are truncated with "..." suffix to prevent memory issues.
*
* <p><b>Unknown properties</b>: For unknown property errors, {@code rawValue}
* is {@code null} since the property name is already in the path.
*
* <p><b>Immutability</b>: All instances are immutable and thread-safe.
*
* @since 3.1
* @see DeferredBindingException#getProblems()
*/
public final class CollectedProblem {
/**
* Maximum length for raw value strings before truncation.
*/
private static final int MAX_RAW_VALUE_LENGTH = 200;
private final JsonPointer path;
private final String message;
private final JavaType targetType;
private final TokenStreamLocation location;
private final Object rawValue; // @Nullable
private final JsonToken token; // @Nullable
public CollectedProblem(JsonPointer path, String message,
JavaType targetType, TokenStreamLocation location,
Object rawValue, JsonToken token) {
this.path = Objects.requireNonNull(path, "path");
this.message = Objects.requireNonNull(message, "message");
this.targetType = targetType;
this.location = location;
this.rawValue = truncateIfNeeded(rawValue);
this.token = token;
}
/**
* @return JSON Pointer path to the problematic field (e.g., "/items/1/date").
* Empty string ("") for root-level problems.
*/
public JsonPointer getPath() { return path; }
/**
* @return Human-readable error message
*/
public String getMessage() { return message; }
/**
* @return Expected Java type for the field (may be null)
*/
public JavaType getTargetType() { return targetType; }
/**
* @return Location in source JSON where problem occurred (may be null)
*/
public TokenStreamLocation getLocation() { return location; }
/**
* @return Raw value from JSON that caused the problem (may be null or truncated).
* For unknown properties, this is null; use the path to identify the property name.
*/
public Object getRawValue() { return rawValue; }
/**
* @return JSON token type at the error location (may be null)
*/
public JsonToken getToken() { return token; }
private static Object truncateIfNeeded(Object value) {
if (value instanceof String) {
String s = (String) value;
if (s.length() > MAX_RAW_VALUE_LENGTH) {
return s.substring(0, MAX_RAW_VALUE_LENGTH - 3) + "...";
}
}
return value;
}
@Override
public String toString() {
return String.format("CollectedProblem[path=%s, message=%s, targetType=%s]",
path, message, targetType);
}
}