Skip to content

Commit

Permalink
improve output for event listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
graemerocher committed Jan 2, 2025
1 parent f364f36 commit e01e206
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,30 @@ public Path pushMethodArgumentResolve(BeanDefinition declaringType, String metho
return this;
}

@Override
public Path pushEventListenerResolve(BeanDefinition<?> declaringType, Argument<?> eventType) {
try {
EventListenerSegment<?, ?> segment = new EventListenerSegment<>(
declaringType,
eventType
);
if (contains(segment)) {
push(segment);
throw new CircularDependencyException(
AbstractBeanResolutionContext.this,
eventType,
CIRCULAR_ERROR_MSG
);
} else {
push(segment);
}
} finally {
traceResolution();
}

return this;
}

@Override
public Path pushFieldResolve(BeanDefinition declaringType, FieldInjectionPoint fieldInjectionPoint) {
try {
Expand Down Expand Up @@ -921,6 +945,51 @@ public String toConsoleString(boolean ansiSupported) {
}
}

/**
* Represents a segment that is an event listener.
* @param <B> The bean type
* @param <T> The event type
*/
public static class EventListenerSegment<B, T> extends AbstractSegment<B, T> implements CallableInjectionPoint<B> {
/**
* @param declaringClass The declaring class
* @param eventType The argument
*/
EventListenerSegment(
BeanDefinition<B> declaringClass,
Argument<T> eventType) {
super(declaringClass, null, eventType.getName(), eventType);
}

@Override
public String toConsoleString(boolean ansiSupported) {
if (ansiSupported) {
String event = getArgument().getTypeString(TypeFormat.ANSI_SIMPLE);
return event + " ➡️ " +
getDeclaringBean().getBeanDescription(TypeFormat.ANSI_SHORTENED);
} else {
String event = getArgument().getTypeString(TypeFormat.SIMPLE);
return event + " -> " +
getDeclaringBean().getBeanDescription(TypeFormat.SHORTENED);
}
}

@Override
public InjectionPoint<B> getInjectionPoint() {
return this;
}

@Override
public Argument<?>[] getArguments() {
return new Argument[] { getArgument() };
}

@Override
public BeanDefinition<B> getDeclaringBean() {
return getDeclaringType();
}
}

/**
* A segment that represents a method.
*/
Expand Down Expand Up @@ -1213,7 +1282,14 @@ void outputArguments(StringBuilder baseString, Argument[] arguments, boolean ans
baseString.append(AnsiColour.RESET);
}
}

if (i != arguments.length - 1) {
Argument<?> next = arguments[i + 1];
if (getDeclaringType().getBeanType().isSynthetic() &&
next.getName().startsWith("$")) {
// skip synthetic arguments
break;
}
baseString.append(", ");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,14 @@ interface Path extends Deque<Segment<?, ?>>, AutoCloseable {
*/
Path pushMethodArgumentResolve(BeanDefinition declaringType, String methodName, Argument argument, Argument[] arguments);

/**
* Push resolution of an event listener
* @param declaringType The declaration type
* @param eventType The event type
* @return The path
*/
Path pushEventListenerResolve(BeanDefinition<?> declaringType, Argument<?> eventType);

/**
* Push an unresolved field onto the queue.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,12 @@ void startTrace(
.walk(s ->
s.dropWhile(f ->
(INTERNAL_PACKAGES.stream().anyMatch(p -> f.getClassName().startsWith(p)) || f.getDeclaringClass().isSynthetic()) &&
// capture startup beans
!(f.getClassName().equals(DefaultBeanContext.class.getName()) && f.getMethodName().equals("start")))
// capture startup beans
!(f.getClassName().equals(DefaultBeanContext.class.getName()) && f.getMethodName().equals("start")))
.limit(3)
.collect(Collectors.toList())
);
String beanName;
if (beanType.getType().isSynthetic()) {
beanName = beanDefinition.getTypeInformation().getBeanTypeString(TypeInformation.TypeFormat.ANSI_SIMPLE);
} else {
beanName = beanType
.getBeanTypeString(TypeInformation.TypeFormat.ANSI_SIMPLE);
}
String beanName = getBeanName(beanType, beanDefinition);
switch (this) {
case STANDARD_OUT -> {
System.out.println();
Expand All @@ -152,6 +146,17 @@ void startTrace(
}
}

private static String getBeanName(Argument<?> beanType, BeanDefinition<?> beanDefinition) {
String beanName;
if (beanType.getType().isSynthetic()) {
beanName = beanDefinition.getTypeInformation().getBeanTypeString(TypeInformation.TypeFormat.ANSI_SIMPLE);
} else {
beanName = beanType
.getBeanTypeString(TypeInformation.TypeFormat.ANSI_SIMPLE);
}
return beanName;
}

<T> void traceBeanResolved(
BeanResolutionContext resolutionContext,
@NonNull Argument<T> beanType,
Expand Down Expand Up @@ -208,8 +213,9 @@ void traceValueResolved(
System.out.print(AnsiColour.formatObject(value));
if (origin != null) {
System.out.println(" (Origin: " + AnsiColour.brightYellow(origin.location()) + ")");
} else {
System.out.println();
}
System.out.println();
}
}
}
Expand Down Expand Up @@ -245,20 +251,22 @@ void traceSegment(BeanResolutionContext context) {
BeanResolutionContext.Path path = context.getPath();
BeanResolutionContext.Segment<?, ?> segment = path.peek();
if (segment != null) {
BeanDefinition<?> declaringType = segment.getDeclaringType();
if (declaringType == null || !declaringType.getBeanType().isSynthetic()) {

int size = path.size();
String prefix = "";
if (size > 1) {
String spaces = " ".repeat(size);
prefix = spaces + RIGHT_ARROW_LOOP;
}
String content = prefix + segment.toConsoleString(AnsiColour.isSupported());
// TODO: other output methods
switch (this) {
case STANDARD_OUT -> System.out.println(content);
}
if (segment.getDeclaringType() != null &&
segment.getDeclaringType().getBeanType().isSynthetic() &&
segment.getArgument().getName().startsWith("$")) {
// skip synthetic arguments
return;
}
int size = path.size();
String prefix = "";
if (size > 1) {
String spaces = " ".repeat(size);
prefix = spaces + RIGHT_ARROW_LOOP;
}
String content = prefix + segment.toConsoleString(AnsiColour.isSupported());
// TODO: other output methods
switch (this) {
case STANDARD_OUT -> System.out.println(content);
}
}
}
Expand Down Expand Up @@ -318,25 +326,25 @@ void traceConfiguration(
).toList();

configRefs.forEach(ref -> {
String prefix = ref.stringValue(ConfigurationReader.class, "prefix").orElse(null);
if (prefix != null) {
Argument<?> argument = ref.asArgument();
System.out.print(" ✚ ");
System.out.print(AnsiColour.formatObject(prefix));
System.out.print(RIGHT_ARROW);
System.out.println(TypeInformation.TypeFormat.getTypeString(
TypeInformation.TypeFormat.ANSI_SHORTENED,
argument.getType(),
argument.getTypeVariables()
));
}
});
String prefix = ref.stringValue(ConfigurationReader.class, "prefix").orElse(null);
if (prefix != null) {
Argument<?> argument = ref.asArgument();
System.out.print(" ✚ ");
System.out.print(AnsiColour.formatObject(prefix));
System.out.print(RIGHT_ARROW);
System.out.println(TypeInformation.TypeFormat.getTypeString(
TypeInformation.TypeFormat.ANSI_SHORTENED,
argument.getType(),
argument.getTypeVariables()
));
}
});
System.out.println();
System.out.println(AnsiColour.brightBlue("Applicable Configuration Present: "));
configRefs.stream()
.flatMap(ref -> ref.stringValue(ConfigurationReader.class, "prefix").stream())
.flatMap(prefix -> {
if(prefix.endsWith(".*")) {
if (prefix.endsWith(".*")) {
String eachProperty = prefix.substring(0, prefix.length() - 2);
return environment.getPropertyEntries(eachProperty).stream().flatMap(entry ->
{
Expand Down
23 changes: 19 additions & 4 deletions inject/src/main/java/io/micronaut/context/DefaultBeanContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -1966,7 +1966,10 @@ private <T extends EventListener> List<Map.Entry<Class<?>, ListenersSupplier<T>>
}
List<Map.Entry<Class<?>, ListenersSupplier<T>>> eventToListeners = new ArrayList<>(typeToListener.size());
for (Map.Entry<Class<?>, List<BeanDefinition<T>>> e : typeToListener.entrySet()) {
eventToListeners.add(new AbstractMap.SimpleEntry<>(e.getKey(), new EventListenerListenersSupplier<>(e.getValue())));
eventToListeners.add(new AbstractMap.SimpleEntry<>(e.getKey(), new EventListenerListenersSupplier<>(
Argument.of(listenerType, e.getKey()),
e.getValue()
)));
}
return eventToListeners;
}
Expand Down Expand Up @@ -4131,12 +4134,14 @@ public int hashCode() {
private final class EventListenerListenersSupplier<T extends EventListener> implements ListenersSupplier<T> {

private final List<BeanDefinition<T>> listenersDefinitions;
private final Argument<?> eventType;
// The supplier can be triggered concurrently.
// We allow for the listeners collection to be initialized multiple times.
@SuppressWarnings("java:S3077")
private volatile List<T> listeners;

public EventListenerListenersSupplier(List<BeanDefinition<T>> listenersDefinitions) {
EventListenerListenersSupplier(Argument<?> eventType, List<BeanDefinition<T>> listenersDefinitions) {
this.eventType = eventType;
this.listenersDefinitions = listenersDefinitions;
}

Expand All @@ -4148,10 +4153,20 @@ public Iterable<T> get(BeanResolutionContext beanResolutionContext) {
T listener;
if (beanResolutionContext == null) {
try (BeanResolutionContext context = newResolutionContext(listenersDefinition, null)) {
listener = resolveBeanRegistration(context, listenersDefinition).bean;
try (BeanResolutionContext.Path ignored = context.getPath().pushEventListenerResolve(
listenersDefinition,
eventType
)) {
listener = resolveBeanRegistration(context, listenersDefinition).bean;
}
}
} else {
listener = resolveBeanRegistration(beanResolutionContext, listenersDefinition).bean;
try (BeanResolutionContext.Path ignored = beanResolutionContext.getPath().pushEventListenerResolve(
listenersDefinition,
eventType
)) {
listener = resolveBeanRegistration(beanResolutionContext, listenersDefinition).bean;
}
}
listeners.add(listener);
}
Expand Down
7 changes: 7 additions & 0 deletions inject/src/main/java/io/micronaut/inject/BeanDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ default Argument<T> getGenericBeanType() {

if (includeArguments) {
beanDescription.append(typeFormat.isAnsi() ? AnsiColour.brightCyan("(") : "(");

for (int i = 0; i < arguments.length; i++) {
Argument<?> argument = arguments[i];
if (argument.getName().startsWith("$")) {
Expand All @@ -623,6 +624,12 @@ default Argument<T> getGenericBeanType() {
.append(typeFormat.isAnsi() ? AnsiColour.brightBlue(argumentName) : argumentName);

if (i != arguments.length - 1) {
Argument<?> next = arguments[i + 1];
if (getBeanType().isSynthetic() &&
next.getName().startsWith("$")) {
// skip synthetic arguments
break;
}
beanDescription.append(", ");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.naming.NameUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.ObjectUtils;
import io.micronaut.inject.BeanType;
Expand Down Expand Up @@ -177,8 +178,8 @@ public String toString() {
if (CollectionUtils.isEmpty(supportedAnnotationNames) && CollectionUtils.isEmpty(supportedInterceptorTypes)) {
return "@InterceptorBinding(NONE)";
} else {
return supportedAnnotationNames.keySet().stream().map((name) -> "@InterceptorBinding(" + name + ")").collect(Collectors.joining(" ")) +
supportedInterceptorTypes.stream().map((name) -> "@InterceptorBinding(interceptorType = " + name + ")").collect(Collectors.joining(" "));
return supportedAnnotationNames.keySet().stream().map((name) -> "@InterceptorBinding(" + NameUtils.getShortenedName(name) + ")").collect(Collectors.joining(" ")) +
supportedInterceptorTypes.stream().map((type) -> "@InterceptorBinding(interceptorType = " + NameUtils.getShortenedName(type.getTypeName()) + ")").collect(Collectors.joining(" "));
}
}

Expand Down

0 comments on commit e01e206

Please sign in to comment.