mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[epilogue] Allow custom loggers for generic types (#7452)
Support custom loggers for generic types Improve error messaging for custom loggers with generic type arguments Consistently start all epilogue processor prints with "[EPILOGUE]"
This commit is contained in:
@@ -86,7 +86,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Custom logger classes should have a @CustomLoggerFor annotation",
|
||||
"[EPILOGUE] Custom logger classes should have a @CustomLoggerFor annotation",
|
||||
e);
|
||||
});
|
||||
|
||||
@@ -284,7 +284,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Logger classes must have a public no-argument constructor",
|
||||
"[EPILOGUE] Logger classes must have a public no-argument constructor",
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
@@ -306,7 +306,17 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Multiple custom loggers detected for type " + targetType,
|
||||
"[EPILOGUE] Multiple custom loggers detected for type " + targetType,
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (annotatedElement instanceof TypeElement t && !t.getTypeParameters().isEmpty()) {
|
||||
processingEnv
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"[EPILOGUE] Custom logger classes cannot take generic type arguments",
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
@@ -318,7 +328,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Not a subclass of ClassSpecificLogger<" + targetType + ">",
|
||||
"[EPILOGUE] Not a subclass of ClassSpecificLogger<" + targetType + ">",
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
@@ -368,7 +378,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Could not write logger file for " + clazz.getQualifiedName(),
|
||||
"[EPILOGUE] Could not write logger file for " + clazz.getQualifiedName(),
|
||||
clazz);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
@@ -22,13 +22,22 @@ public class ConfiguredLoggerHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public boolean isLoggable(Element element) {
|
||||
return m_customLoggers.containsKey(dataType(element));
|
||||
return m_customLoggers.keySet().stream()
|
||||
.anyMatch(m -> m_processingEnv.getTypeUtils().isAssignable(dataType(element), m));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
var dataType = dataType(element);
|
||||
var loggerType = m_customLoggers.get(dataType);
|
||||
var loggerType =
|
||||
m_customLoggers.entrySet().stream()
|
||||
.filter(
|
||||
e -> {
|
||||
return m_processingEnv.getTypeUtils().isAssignable(dataType, e.getKey());
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.getValue();
|
||||
|
||||
return "Epilogue."
|
||||
+ StringUtils.lowerCamelCase(loggerType.asElement().getSimpleName())
|
||||
|
||||
@@ -1470,6 +1470,106 @@ class AnnotationProcessorTest {
|
||||
assertLoggerGenerates(source, expectedGeneratedSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customGenericLogger() {
|
||||
String source =
|
||||
"""
|
||||
package edu.wpi.first.epilogue;
|
||||
|
||||
import edu.wpi.first.epilogue.logging.*;
|
||||
import edu.wpi.first.math.numbers.*;
|
||||
import edu.wpi.first.math.Num;
|
||||
import edu.wpi.first.math.Vector;
|
||||
|
||||
@CustomLoggerFor(Vector.class)
|
||||
class VectorLogger extends ClassSpecificLogger<Vector<?>> {
|
||||
public VectorLogger() {
|
||||
super((Class) Vector.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DataLogger dataLogger, Vector<?> object) {
|
||||
// Implementation is irrelevant
|
||||
}
|
||||
}
|
||||
|
||||
@Logged
|
||||
class Example {
|
||||
Vector<N3> vec;
|
||||
}
|
||||
""";
|
||||
|
||||
String expectedGeneratedSource =
|
||||
"""
|
||||
package edu.wpi.first.epilogue;
|
||||
|
||||
import edu.wpi.first.epilogue.Logged;
|
||||
import edu.wpi.first.epilogue.Epilogue;
|
||||
import edu.wpi.first.epilogue.logging.ClassSpecificLogger;
|
||||
import edu.wpi.first.epilogue.logging.DataLogger;
|
||||
|
||||
public class ExampleLogger extends ClassSpecificLogger<Example> {
|
||||
public ExampleLogger() {
|
||||
super(Example.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DataLogger dataLogger, Example object) {
|
||||
if (Epilogue.shouldLog(Logged.Importance.DEBUG)) {
|
||||
Epilogue.vectorLogger.tryUpdate(dataLogger.getSubLogger("vec"), object.vec, Epilogue.getConfig().errorHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
assertLoggerGenerates(source, expectedGeneratedSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void genericLoggerForGenericType() {
|
||||
String source =
|
||||
"""
|
||||
package edu.wpi.first.epilogue;
|
||||
|
||||
import edu.wpi.first.epilogue.logging.*;
|
||||
|
||||
class Generic<T> { }
|
||||
|
||||
@CustomLoggerFor(Generic.class)
|
||||
// Invalid: loggers cannot take type arguments
|
||||
class GenericLogger<T> extends ClassSpecificLogger<Generic<T>> {
|
||||
public GenericLogger() {
|
||||
super((Class) Generic.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DataLogger dataLogger, Generic<T> object) {
|
||||
// Implementation is irrelevant
|
||||
}
|
||||
}
|
||||
|
||||
@Logged
|
||||
class Example {
|
||||
Generic<String> genericField;
|
||||
}
|
||||
""";
|
||||
|
||||
Compilation compilation =
|
||||
javac()
|
||||
.withOptions(kJavaVersionOptions)
|
||||
.withProcessors(new AnnotationProcessor())
|
||||
.compile(JavaFileObjects.forSourceString("edu.wpi.first.epilogue.Example", source));
|
||||
|
||||
assertThat(compilation).failed();
|
||||
assertThat(compilation).hadErrorCount(1);
|
||||
|
||||
assertCompilationError(
|
||||
"[EPILOGUE] Custom logger classes cannot take generic type arguments",
|
||||
9,
|
||||
1,
|
||||
compilation.errors().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void warnsAboutNonLoggableFields() {
|
||||
String source =
|
||||
|
||||
Reference in New Issue
Block a user