001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package dev.metaschema.core.model; 007 008import com.fasterxml.jackson.core.JsonLocation; 009 010import javax.xml.stream.Location; 011 012import edu.umd.cs.findbugs.annotations.NonNull; 013 014/** 015 * A simple implementation of {@link IMetaschemaData} that stores location 016 * information from various parser sources. 017 * <p> 018 * This class can be used both for bound object metadata during parsing and for 019 * validation context in error messages. 020 */ 021public final class SimpleResourceLocation implements IMetaschemaData { 022 /** A constant representing an unknown location. */ 023 @NonNull 024 public static final IMetaschemaData UNKNOWN = new SimpleResourceLocation(-1, -1, -1L, -1L); 025 026 private final int line; 027 private final int column; 028 private final long charOffset; 029 private final long byteOffset; 030 031 /** 032 * Construct a new resource location with the specified values. 033 * 034 * @param line 035 * the line number (1-based), or -1 if unknown 036 * @param column 037 * the column number (1-based), or -1 if unknown 038 * @param charOffset 039 * the character offset (0-based), or -1 if unknown 040 * @param byteOffset 041 * the byte offset (0-based), or -1 if unknown 042 */ 043 public SimpleResourceLocation(int line, int column, long charOffset, long byteOffset) { 044 this.line = line; 045 this.column = column; 046 this.charOffset = charOffset; 047 this.byteOffset = byteOffset; 048 } 049 050 /** 051 * Create a resource location from an XML stream location. 052 * 053 * @param location 054 * the XML stream location, may be {@code null} 055 * @return a new resource location, or {@link #UNKNOWN} if the input is null 056 */ 057 @NonNull 058 public static IMetaschemaData fromXmlLocation(Location location) { 059 if (location == null) { 060 return UNKNOWN; 061 } 062 return new SimpleResourceLocation( 063 location.getLineNumber(), 064 location.getColumnNumber(), 065 location.getCharacterOffset(), 066 -1L); 067 } 068 069 /** 070 * Create a resource location from a Jackson JSON location. 071 * 072 * @param location 073 * the JSON location, may be {@code null} 074 * @return a new resource location, or {@link #UNKNOWN} if the input is null 075 */ 076 @NonNull 077 public static IMetaschemaData fromJsonLocation(JsonLocation location) { 078 if (location == null) { 079 return UNKNOWN; 080 } 081 return new SimpleResourceLocation( 082 location.getLineNr(), 083 location.getColumnNr(), 084 location.getCharOffset(), 085 location.getByteOffset()); 086 } 087 088 /** 089 * Create a resource location with just line and column information. 090 * 091 * @param line 092 * the line number (1-based), or -1 if unknown 093 * @param column 094 * the column number (1-based), or -1 if unknown 095 * @return a new resource location 096 */ 097 @NonNull 098 public static IMetaschemaData of(int line, int column) { 099 return new SimpleResourceLocation(line, column, -1L, -1L); 100 } 101 102 @Override 103 public int getLine() { 104 return line; 105 } 106 107 @Override 108 public int getColumn() { 109 return column; 110 } 111 112 @Override 113 public long getCharOffset() { 114 return charOffset; 115 } 116 117 @Override 118 public long getByteOffset() { 119 return byteOffset; 120 } 121 122 @Override 123 public String toString() { 124 StringBuilder sb = new StringBuilder(); 125 if (line >= 0) { 126 sb.append(line); 127 if (column >= 0) { 128 sb.append(':').append(column); 129 } 130 } else { 131 sb.append("unknown"); 132 } 133 return sb.toString(); 134 } 135}