001/* 002 * Copyright (C) 2022 - 2023, the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.github.ascopes.jct.diagnostics; 017 018import static java.util.Collections.unmodifiableList; 019import static java.util.Objects.requireNonNull; 020 021import io.github.ascopes.jct.utils.ToStringBuilder; 022import java.time.Instant; 023import java.util.List; 024import java.util.Locale; 025import javax.tools.Diagnostic; 026import javax.tools.JavaFileObject; 027import org.apiguardian.api.API; 028import org.apiguardian.api.API.Status; 029import org.jspecify.annotations.Nullable; 030 031/** 032 * A wrapper around a {@link Diagnostic} which contains additional information about where the 033 * diagnostic was reported. 034 * 035 * @param <S> the file type. 036 * @author Ashley Scopes 037 * @since 0.0.1 038 */ 039@API(since = "0.0.1", status = Status.STABLE) 040public class TraceDiagnostic<S extends JavaFileObject> implements Diagnostic<S> { 041 042 private final Instant timestamp; 043 private final long threadId; 044 private final @Nullable String threadName; 045 private final List<StackTraceElement> stackTrace; 046 private final Diagnostic<? extends S> original; 047 048 /** 049 * Initialize this diagnostic. 050 * 051 * @param timestamp the timestamp. 052 * @param threadId the thread ID. 053 * @param threadName the thread name, or {@code null} if not known. 054 * @param stackTrace the stacktrace. 055 * @param original the original diagnostic that was reported. 056 */ 057 public TraceDiagnostic( 058 Instant timestamp, 059 long threadId, 060 String threadName, 061 List<StackTraceElement> stackTrace, 062 Diagnostic<? extends S> original 063 ) { 064 this.timestamp = requireNonNull(timestamp, "timestamp"); 065 this.threadId = threadId; 066 this.threadName = threadName; 067 this.stackTrace = unmodifiableList(requireNonNull(stackTrace, "stackTrace")); 068 this.original = requireNonNull(original, "original"); 069 } 070 071 @Override 072 public Kind getKind() { 073 return original.getKind(); 074 } 075 076 @Override 077 public S getSource() { 078 return original.getSource(); 079 } 080 081 @Override 082 public long getPosition() { 083 return original.getPosition(); 084 } 085 086 @Override 087 public long getStartPosition() { 088 return original.getStartPosition(); 089 } 090 091 @Override 092 public long getEndPosition() { 093 return original.getEndPosition(); 094 } 095 096 @Override 097 public long getLineNumber() { 098 return original.getLineNumber(); 099 } 100 101 @Override 102 public long getColumnNumber() { 103 return original.getColumnNumber(); 104 } 105 106 @Override 107 public String getCode() { 108 return original.getCode(); 109 } 110 111 @Override 112 public String getMessage(@Nullable Locale locale) { 113 return original.getMessage(locale); 114 } 115 116 /** 117 * Get the timestamp that the diagnostic was created at. 118 * 119 * @return the diagnostic timestamp. 120 */ 121 public Instant getTimestamp() { 122 return timestamp; 123 } 124 125 /** 126 * Get the thread ID for the thread that created this diagnostic. 127 * 128 * @return the thread ID. 129 */ 130 public long getThreadId() { 131 return threadId; 132 } 133 134 /** 135 * Get the thread name for the thread that created this diagnostic. 136 * 137 * @return the thread name, if known, or else {@code null}. 138 */ 139 public String getThreadName() { 140 return threadName; 141 } 142 143 /** 144 * Get the stacktrace of where the diagnostic was written from. 145 * 146 * @return the stacktrace, in an unmodifiable list. 147 */ 148 public List<StackTraceElement> getStackTrace() { 149 return stackTrace; 150 } 151 152 @Override 153 public String toString() { 154 return new ToStringBuilder(this) 155 .attribute("timestamp", timestamp) 156 .attribute("threadId", threadId) 157 .attribute("threadName", threadName) 158 .attribute("kind", original.getKind()) 159 .attribute("code", original.getCode()) 160 .attribute("column", original.getColumnNumber()) 161 .attribute("line", original.getLineNumber()) 162 .attribute("message", original.getMessage(Locale.ROOT)) 163 .toString(); 164 } 165}