001/* 002 * Copyright (C) 2022 - 2024, 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.jspecify.annotations.Nullable; 028 029/** 030 * A wrapper around a {@link Diagnostic} which contains additional information about where the 031 * diagnostic was reported. 032 * 033 * @param <S> the file type. 034 * @author Ashley Scopes 035 * @since 0.0.1 036 */ 037public class TraceDiagnostic<S extends JavaFileObject> implements Diagnostic<S> { 038 039 private final Instant timestamp; 040 private final long threadId; 041 private final @Nullable String threadName; 042 private final List<StackTraceElement> stackTrace; 043 private final Diagnostic<? extends S> original; 044 045 /** 046 * Initialize this diagnostic. 047 * 048 * @param timestamp the timestamp. 049 * @param threadId the thread ID. 050 * @param threadName the thread name, or {@code null} if not known. 051 * @param stackTrace the stacktrace. 052 * @param original the original diagnostic that was reported. 053 */ 054 public TraceDiagnostic( 055 Instant timestamp, 056 long threadId, 057 @Nullable String threadName, 058 List<StackTraceElement> stackTrace, 059 Diagnostic<? extends S> original 060 ) { 061 this.timestamp = requireNonNull(timestamp, "timestamp"); 062 this.threadId = threadId; 063 this.threadName = threadName; 064 this.stackTrace = unmodifiableList(requireNonNull(stackTrace, "stackTrace")); 065 this.original = requireNonNull(original, "original"); 066 } 067 068 @Override 069 public Kind getKind() { 070 return original.getKind(); 071 } 072 073 @Nullable 074 @Override 075 public S getSource() { 076 return original.getSource(); 077 } 078 079 @Override 080 public long getPosition() { 081 return original.getPosition(); 082 } 083 084 @Override 085 public long getStartPosition() { 086 return original.getStartPosition(); 087 } 088 089 @Override 090 public long getEndPosition() { 091 return original.getEndPosition(); 092 } 093 094 @Override 095 public long getLineNumber() { 096 return original.getLineNumber(); 097 } 098 099 @Override 100 public long getColumnNumber() { 101 return original.getColumnNumber(); 102 } 103 104 @Nullable 105 @Override 106 public String getCode() { 107 return original.getCode(); 108 } 109 110 @Override 111 public String getMessage(@Nullable Locale locale) { 112 return original.getMessage(locale); 113 } 114 115 /** 116 * Get the timestamp that the diagnostic was created at. 117 * 118 * @return the diagnostic timestamp. 119 */ 120 public Instant getTimestamp() { 121 return timestamp; 122 } 123 124 /** 125 * Get the thread ID for the thread that created this diagnostic. 126 * 127 * @return the thread ID. 128 */ 129 public long getThreadId() { 130 return threadId; 131 } 132 133 /** 134 * Get the thread name for the thread that created this diagnostic. 135 * 136 * @return the thread name, if known, or else {@code null}. 137 */ 138 @Nullable 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}