diff --git a/README.md b/README.md index 86d014c..53059fc 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![Maven Central](https://img.shields.io/maven-central/v/org.microbean/microbean-event.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.microbean/microbean-event) +![0% AI](https://img.shields.io/badge/%F0%9F%A4%96_AI-0%25_%F0%9F%8C%BC-brightgreen) + The microBean™ Event project provides classes and interfaces assisting with implementing simple Java events. # Status @@ -27,7 +29,7 @@ dependency: org.microbean microbean-event - 0.0.3 + 0.0.4 ``` diff --git a/pom.xml b/pom.xml index a38cded..a8ba7ec 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ ${project.organization.name}. All rights reserved.]]> <a href="${project.url}" target="_top"><span style="font-family:Lobster, cursive;">µb</span> ${project.artifactId}</a> ${project.version} - https://microbean.github.io/microbean-assign/apidocs/,https://microbean.github.io/microbean-attributes/apidocs/,https://microbean.github.io/microbean-bean/apidocs/,https://microbean.github.io/microbean-construct/apidocs/,https://microbean.github.io/microbean-qualifier/apidocs/ + https://microbean.github.io/microbean-assign/apidocs/,https://microbean.github.io/microbean-bean/apidocs/,https://microbean.github.io/microbean-construct/apidocs/,https://microbean.github.io/microbean-qualifier/apidocs/ 2 @@ -127,25 +127,19 @@ org.microbean microbean-assign - 0.0.11 - - - - org.microbean - microbean-attributes - 0.0.5 + 0.0.14 org.microbean microbean-bean - 0.0.22 + 0.0.23 org.microbean microbean-construct - 0.0.18 + 0.0.24 @@ -159,12 +153,6 @@ compile - - org.microbean - microbean-attributes - compile - - org.microbean microbean-bean @@ -324,7 +312,7 @@ com.puppycrawl.tools checkstyle - 12.3.0 + 13.2.0 @@ -345,7 +333,7 @@ maven-compiler-plugin - 3.14.1 + 3.15.0 -Xlint:all @@ -355,7 +343,7 @@ maven-dependency-plugin - 3.9.0 + 3.10.0 maven-deploy-plugin @@ -457,7 +445,7 @@ org.codehaus.mojo versions-maven-plugin - 2.20.1 + 2.21.0 io.smallrye @@ -467,7 +455,7 @@ org.sonatype.central central-publishing-maven-plugin - 0.9.0 + 0.10.0 true central.sonatype.com diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 9d65a61..b7ea74a 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2025 microBean™. + * Copyright © 2025–2026 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -23,7 +23,6 @@ requires transitive java.compiler; requires transitive org.microbean.assign; - requires transitive org.microbean.attributes; requires transitive org.microbean.bean; requires org.microbean.constant; requires transitive org.microbean.construct; diff --git a/src/main/java/org/microbean/event/EventListener.java b/src/main/java/org/microbean/event/EventListener.java index 95e4a71..65b57f4 100644 --- a/src/main/java/org/microbean/event/EventListener.java +++ b/src/main/java/org/microbean/event/EventListener.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2025 microBean™. + * Copyright © 2025–2026 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,16 +17,14 @@ import javax.lang.model.element.Element; +import org.microbean.assign.Annotated; import org.microbean.assign.Aggregate; -import org.microbean.assign.AttributedElement; -import org.microbean.assign.AttributedType; -import org.microbean.assign.AttributedTyped; import org.microbean.bean.ReferencesSelector; /** - * An {@link java.util.EventListener EventListener}, an {@link Aggregate}, and an {@link AttributedTyped} that - * {@linkplain #eventReceived(Object, ReferencesSelector) receives} events. + * An {@link java.util.EventListener EventListener}, and an {@link Aggregate} that {@linkplain #eventReceived(Object, + * ReferencesSelector) receives} events. * * @param the result of reception; almost always {@link Void} * @@ -56,32 +54,12 @@ // * eventDependency() includes VariableElement-representing-e and nothing else // * receive() calls onEvent() supplying it with event and a @Complicated Frob acquired via r // -// TODO: Does this actually need to be an AttributedTyped? -public interface EventListener extends AttributedTyped, Aggregate, java.util.EventListener { +public interface EventListener extends Aggregate, java.util.EventListener { /** - * Returns a non-{@code null}, determinate {@link AttributedType} describing the kinds of events this {@link - * EventListener} is prepared to handle. - * - *

The default implementation of this method extracts this information from an invocation of the {@link - * #eventDependency()} method ({@linkplain #eventDependency() q.v.}).

- * - * @return a non-{@code null}, determinate {@link AttributedType} - * - * @exception NullPointerException if the default implementation of this method receives a {@code null} return value - * from an invocation of the {@link #eventDependency()} method - * - * @see #eventDependency() - */ - @Override // AttributedTypedAggregate (AttributedTyped) - public default AttributedType attributedType() { - return this.eventDependency().attributedType(); - } - - /** - * Returns a non-{@code null}, determinate, immutable {@link SequencedSet} of {@link AttributedElement}s representing + * Returns a non-{@code null}, determinate, immutable {@link SequencedSet} of {@link Element}s representing * dependencies this {@link EventListener} has that must be resolved before any invocation of the {@link - * #eventReceived(Object, ReferencesSelector)} method may properly occur. + * #eventReceived(Object, ReferencesSelector2)} method may properly occur. * *

Implementations of this method must not include a result of any invocation of the {@link #eventDependency()} * method as an element of the return value.

@@ -89,38 +67,35 @@ public default AttributedType attributedType() { *

The default implementation of this method returns an {@linkplain SequencedSet#isEmpty() empty} {@link * SequencedSet}. Overrides are expected.

* - * @return a non-{@code null}, determinate, immutable {@link SequencedSet} of {@link AttributedElement}s + * @return a non-{@code null}, determinate, immutable {@link SequencedSet} of {@link Element}s * - * @see #eventReceived(Object, ReferencesSelector) + * @see #eventReceived(Object, ReferencesSelector2) * * @see #eventDependency() */ // Returns dependencies that are not the event dependency. These are resolved by the system. Think of an observer // method with an observed parameter and other parameters. The other parameters are these dependencies. - @Override // AttributedTypedAggregate (Aggregate) - public default SequencedSet dependencies() { + @Override // Aggregate + public default SequencedSet> dependencies() { return Aggregate.super.dependencies(); } /** - * Returns a non-{@code null}, determinate {@link AttributedElement} representing the program element for which an - * event is destined. + * Returns a non-{@code null}, determinate {@link Element} representing the program element for which an event is + * destined. * *

The result of an invocation of this method must not appear as an element of the return value of an invocation of * the {@link #dependencies()} method.

* - *

Note that the default implementation of the {@link #attributedType()} method calls this method and requires it - * to return a non-{@code null} value.

- * - * @return a non-{@code null}, determinate {@link AttributedElement} + * @return a non-{@code null}, determinate {@link Element} * * @see #dependencies() */ - // An AttributedElement describing the event event "slot" (the observed parameter). + // An Element describing the event event "slot" (the observed parameter). // Conceptually just another dependency (see dependencies()) but it is supplied by the user, not the system. // Normally a method parameter. // T's argument (the event event type) must be among its types. - public AttributedElement eventDependency(); + public Annotated eventDependency(); /** * Receives and handles an event, normally as delivered by an invocation of the {@link Events#fire(TypeMirror, List, diff --git a/src/main/java/org/microbean/event/EventQualifiersMatcher.java b/src/main/java/org/microbean/event/EventQualifiersMatcher.java index bb48d3c..fec896b 100644 --- a/src/main/java/org/microbean/event/EventQualifiersMatcher.java +++ b/src/main/java/org/microbean/event/EventQualifiersMatcher.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2025 microBean™. + * Copyright © 2025–2026 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -15,23 +15,23 @@ import java.util.Collection; +import javax.lang.model.element.AnnotationMirror; + import org.microbean.assign.Matcher; import org.microbean.assign.Qualifiers; -import org.microbean.attributes.Attributes; - import static java.util.Objects.requireNonNull; /** * A {@link Matcher} encapsulating CDI-compatible event + * href="https://jakarta.ee/specifications/cdi/4.1/jakarta-cdi-spec-4.1#observer_resolution">CDI-compatible event * qualifier matching rules. * * @author Laird Nelson * * @see #test(Collection, Collection) */ -public final class EventQualifiersMatcher implements Matcher, Collection> { +public final class EventQualifiersMatcher implements Matcher, Collection> { /* @@ -67,30 +67,30 @@ public EventQualifiersMatcher(final Qualifiers qualifiers) { /** * Returns {@code true} if and only if either the {@linkplain org.microbean.assign.Qualifiers#qualifiers(Collection) - * qualifiers present} in {@code receiverAttributes} are {@linkplain Collection#isEmpty() empty}, or if the collection - * of {@linkplain org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code - * payloadAttributes} {@linkplain Collection#containsAll(Collection) contains all} of the {@linkplain - * org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code receiverAttributes}. + * qualifiers present} in {@code receiverAnnotations} are {@linkplain Collection#isEmpty() empty}, or if the + * collection of {@linkplain org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code + * payloadAnnotations} {@linkplain Collection#containsAll(Collection) contains all} of the {@linkplain + * org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code receiverAnnotations}. * - * @param receiverAttributes a {@link Collection} of {@link Attributes} instances; must not be {@code null} + * @param receiverAnnotations a {@link Collection} of {@link AnnotationMirror} instances; must not be {@code null} * - * @param payloadAttributes a {@link Collection} of {@link Attributes} instances; must not be {@code null} + * @param payloadAnnotations a {@link Collection} of {@link AnnotationMirror} instances; must not be {@code null} * * @return {@code true} if and only if either the {@linkplain org.microbean.assign.Qualifiers#qualifiers(Collection) - * qualifiers present} in {@code receiverAttributes} are {@linkplain Collection#isEmpty() empty}, or if the collection - * of {@linkplain org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code - * payloadAttributes} {@linkplain Collection#containsAll(Collection) contains all} of the {@linkplain - * org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code receiverAttributes} + * qualifiers present} in {@code receiverAnnotations} are {@linkplain Collection#isEmpty() empty}, or if the + * collection of {@linkplain org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code + * payloadAnnotations} {@linkplain Collection#containsAll(Collection) contains all} of the {@linkplain + * org.microbean.assign.Qualifiers#qualifiers(Collection) qualifiers present} in {@code receiverAnnotations} * * @exception NullPointerException if either argument is {@code null} */ @Override // Matcher>, Collection>> - public final boolean test(final Collection receiverAttributes, - final Collection payloadAttributes) { + public final boolean test(final Collection receiverAnnotations, + final Collection payloadAnnotations) { // "An event is delivered to an observer method if...the observer method has no event qualifiers or has a subset of // the event qualifiers." - final Collection receiverQualifiers = qualifiers.qualifiers(receiverAttributes); - return receiverQualifiers.isEmpty() || qualifiers.qualifiers(payloadAttributes).containsAll(receiverQualifiers); + final Collection receiverQualifiers = qualifiers.qualifiers(receiverAnnotations); + return receiverQualifiers.isEmpty() || qualifiers.qualifiers(payloadAnnotations).containsAll(receiverQualifiers); } } diff --git a/src/main/java/org/microbean/event/Events.java b/src/main/java/org/microbean/event/Events.java index eb1f9b9..6196702 100644 --- a/src/main/java/org/microbean/event/Events.java +++ b/src/main/java/org/microbean/event/Events.java @@ -1,6 +1,6 @@ /* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- * - * Copyright © 2025 microBean™. + * Copyright © 2025–2026 microBean™. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -16,18 +16,20 @@ import java.util.Iterator; import java.util.List; -import javax.lang.model.type.TypeMirror; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; -import org.microbean.assign.AttributedElement; -import org.microbean.assign.AttributedType; +import javax.lang.model.type.TypeMirror; -import org.microbean.attributes.Attributes; +import org.microbean.assign.Annotated; import org.microbean.bean.Qualifiers; import org.microbean.bean.ReferencesSelector; import org.microbean.construct.Domain; +import org.microbean.construct.type.UniversalType; + import static java.util.Objects.requireNonNull; /** @@ -37,61 +39,64 @@ */ // Deliberately not final. public class Events { - + private final EventTypes eventTypes; - private final Qualifiers qualifiers; - + private final org.microbean.assign.Qualifiers aq; + private final EventTypeMatcher eventTypeMatcher; private final EventQualifiersMatcher eventQualifiersMatcher; - private final AttributedType eventListenerAttributedType; + private final Annotated eventListenerAnnotated; /** * Creates a new {@link Events}. * - * @param eventTypes an {@link EventTypes}; must not be {@code null} + * @param domain a non-{@code null} Domain + * + * @param eventTypes a non-{@code null} {@link EventTypes} * - * @param qualifiers a {@link Qualifiers}; must not be {@code null} + * @param aq a non-{@code null} {@link org.microbean.assign.Qualifiers} * - * @param eventTypeMatcher an {@link EventTypeMatcher}; must not be {@code null} + * @param bq a non-{@code null} {@link Qualifiers} * - * @param eventQualifiersMatcher an {@link EventQualifiersMatcher}; must not be {@code null} + * @param eventTypeMatcher a non-{@code null} {@link EventTypeMatcher} + * + * @param eventQualifiersMatcher a non-{@code null} {@link EventQualifiersMatcher} * * @exception NullPointerException if any argument is {@code null} */ - public Events(final EventTypes eventTypes, - final Qualifiers qualifiers, + public Events(final Domain domain, + final EventTypes eventTypes, + final org.microbean.assign.Qualifiers aq, + final Qualifiers bq, final EventTypeMatcher eventTypeMatcher, final EventQualifiersMatcher eventQualifiersMatcher) { super(); this.eventTypes = requireNonNull(eventTypes, "eventTypes"); - this.qualifiers = requireNonNull(qualifiers, "qualifiers"); + this.aq = requireNonNull(aq, "aq"); this.eventTypeMatcher = requireNonNull(eventTypeMatcher, "eventTypeMatcher"); this.eventQualifiersMatcher = requireNonNull(eventQualifiersMatcher, "eventQualifiersMatcher"); - final Domain d = eventTypes.domain(); - this.eventListenerAttributedType = - new AttributedType(d.declaredType(d.typeElement(EventListener.class.getCanonicalName()), - d.wildcardType(), - d.wildcardType(null, d.javaLangObjectType())), - this.qualifiers.anyQualifiers()); + this.eventListenerAnnotated = + Annotated.of(new UniversalType(bq.anyQualifiers(), + domain.declaredType(domain.typeElement(EventListener.class.getCanonicalName()), + domain.wildcardType(), + domain.wildcardType()), + domain)); } /** * Delivers ("fires") the supplied {@code event} to suitable {@link EventListener}s. * - *

A suitable {@link EventListener} is one whose {@link EventListener#attributedType()} method returns an {@link - * AttributedType} - * * @param typeArgumentSource handwave here about the specified type and type argument substitution * - * @param attributes a {@link List} of {@link Attributes} qualifying the event; must not be {@code null} + * @param annotations a {@link List} of {@link AnnotationMirror}s qualifying the event; must not be {@code null} * * @param event the event; must not be {@code null} * - * @param rs a {@link ReferencesSelector}; used to find {@link EventListener EventListener<?, ?>} references; must not be - * {@code null} + * @param rs a {@link ReferencesSelector}; used to find {@link EventListener EventListener<?, ?>} references; + * must not be {@code null} * * @exception NullPointerException if any argument is {@code null} * @@ -103,21 +108,22 @@ public Events(final EventTypes eventTypes, */ // Deliberately final. public final void fire(final TypeMirror typeArgumentSource, - final List attributes, + final List annotations, final Object event, final ReferencesSelector rs) { final EventTypeList eventTypes = this.eventTypes.eventTypes(typeArgumentSource, event); - final List eventQualifiers = this.qualifiers.qualifiers(attributes); + final List eventQualifiers = this.aq.qualifiers(annotations); final Iterator> i = - rs.>references(this.eventListenerAttributedType).iterator(); + rs.>references(this.eventListenerAnnotated).iterator(); while (i.hasNext()) { final EventListener el = i.next(); try { - final AttributedType slot = el.attributedType(); - if (slot == null || !this.eventQualifiersMatcher.test(this.qualifiers.qualifiers(slot.attributes()), eventQualifiers)) { + final Annotated slot = el.eventDependency(); + if (slot == null || + !this.eventQualifiersMatcher.test(this.aq.qualifiers(slot.annotations()), eventQualifiers)) { continue; } - final TypeMirror slotType = slot.type(); + final TypeMirror slotType = slot.annotated().asType(); for (final TypeMirror eventType : eventTypes) { if (this.eventTypeMatcher.test(slotType, eventType)) { // This level of indirection permits asynchronous notification. @@ -144,8 +150,8 @@ public final void fire(final TypeMirror typeArgumentSource, *

Overrides of this method must not call the {@link #fire(TypeMirror, List, Object, ReferencesSelector)} method, * or an infinite loop may result.

* - * @param el an {@link EventListener} that has been determined to be suitable for the supplied {@code event}; must not - * be {@code null} + * @param el an {@link EventListener} that has been determined to be suitable for the supplied {@code event}; must + * not be {@code null} * * @param event the event to deliver; must not be {@code null} *