diff --git a/README.md b/README.md index e9042fe..6c45fca 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ dependency: org.microbean microbean-bean - 0.0.18 + 0.0.19 ``` diff --git a/pom.xml b/pom.xml index 33fca54..9f9ef74 100644 --- a/pom.xml +++ b/pom.xml @@ -125,7 +125,7 @@ org.junit junit-bom - 5.12.2 + 5.13.1 pom import @@ -134,7 +134,7 @@ org.jboss.weld weld-core-bom - 6.0.2.Final + 6.0.3.Final pom import @@ -144,13 +144,13 @@ org.microbean microbean-assign - 0.0.5 + 0.0.6 org.microbean microbean-attributes - 0.0.2 + 0.0.3 @@ -162,7 +162,7 @@ org.microbean microbean-construct - 0.0.10 + 0.0.11 @@ -347,7 +347,7 @@ maven-clean-plugin - 3.4.1 + 3.5.0 @@ -481,7 +481,7 @@ io.smallrye jandex-maven-plugin - 3.3.0 + 3.3.1 org.sonatype.plugins diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 926fbd3..8392da0 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -24,7 +24,7 @@ requires transitive java.compiler; requires transitive org.microbean.assign; requires transitive org.microbean.attributes; - requires org.microbean.constant; - requires transitive org.microbean.construct; + requires org.microbean.constant; + requires org.microbean.construct; } diff --git a/src/main/java/org/microbean/bean/Aggregate.java b/src/main/java/org/microbean/bean/Aggregate.java deleted file mode 100644 index df53a31..0000000 --- a/src/main/java/org/microbean/bean/Aggregate.java +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.Collection; -import java.util.Collections; -import java.util.SequencedSet; - -import java.util.function.Function; - -import static java.util.Collections.unmodifiableSequencedSet; - -import static java.util.LinkedHashSet.newLinkedHashSet; - -/** - * An object with {@linkplain AttributedElement dependencies}. - * - *

By default, {@link Aggregate}s have {@linkplain #EMPTY_DEPENDENCIES no dependencies}.

- * - * @author Laird Nelson - * - * @see #dependencies() - */ -public interface Aggregate { - - - /* - * Static fields. - */ - - - /** - * An immutable, empty {@link SequencedSet} of {@link Assignment}s. - */ - public static final SequencedSet> EMPTY_ASSIGNMENTS = unmodifiableSequencedSet(newLinkedHashSet(0)); - - /** - * An immutable, empty {@link SequencedSet} of {@link AttributedElement}s. - */ - public static final SequencedSet EMPTY_DEPENDENCIES = unmodifiableSequencedSet(newLinkedHashSet(0)); - - - /* - * Default instance methods. - */ - - - /** - * Returns an immutable {@link SequencedSet} of {@link AttributedElement} instances. - * - * @return an immutable {@link SequencedSet} of {@link AttributedElement} instances; never {@code null} - * - * @see AttributedElement - */ - public default SequencedSet dependencies() { - return EMPTY_DEPENDENCIES; - } - - /** - * A convenience method that assigns a contextual reference to each of this {@link Aggregate}'s {@link - * AttributedElement} instances and returns the resulting {@link SequencedSet} of {@link Assignment}s. - * - *

Typically there is no need to override this method.

- * - * @param r a {@link Function} that retrieves a contextual reference suitable for an {@link AttributedType}; if {@link - * #dependencies()} returns a non-empty {@link SequencedSet} then this argument must not be {@code null} - * - * @return an immutable {@link SequencedSet} of {@link Assignment} instances; never {@code null} - * - * @exception NullPointerException if {@code r} is {@code null} - * - * @see References - */ - public default SequencedSet> assign(final Function r) { - final Collection ds = this.dependencies(); - if (ds == null || ds.isEmpty()) { - return EMPTY_ASSIGNMENTS; - } - final SequencedSet> assignments = newLinkedHashSet(ds.size()); - ds.forEach(d -> assignments.add(new Assignment<>(d, r.apply(d.attributedType())))); - return Collections.unmodifiableSequencedSet(assignments); - } - -} diff --git a/src/main/java/org/microbean/bean/Assignment.java b/src/main/java/org/microbean/bean/Assignment.java deleted file mode 100644 index 0541ce4..0000000 --- a/src/main/java/org/microbean/bean/Assignment.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.Objects; - -/** - * An assignment of a contextual reference to an {@link AttributedElement}, usually as completed by - * a {@link References}. - * - * @param the type of contextual reference - * - * @param assignee the {@link AttributedElement}; must not be {@code null} - * - * @param value the contextual reference; may be {@code null} - * - * @author Laird Nelson - */ -// You're going to be tempted to replace the value component with a Supplier component. Don't do it. An assignment is a -// value that belongs to, e.g., a field, so even if the value "came from" none/dependent/prototype scope, it was already -// sourced and "belongs to" the field. -public final record Assignment(AttributedElement assignee, R value) { - - /** - * Creates a new {@link Assignment}. - * - * @param assignee the {@link AttributedElement}; must not be {@code null} - * - * @param value the contextual reference; may be {@code null} - */ - public Assignment { - Objects.requireNonNull(assignee, "assignee"); - } - -} diff --git a/src/main/java/org/microbean/bean/AttributedElement.java b/src/main/java/org/microbean/bean/AttributedElement.java deleted file mode 100644 index a1c8783..0000000 --- a/src/main/java/org/microbean/bean/AttributedElement.java +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.lang.constant.ClassDesc; -import java.lang.constant.Constable; -import java.lang.constant.ConstantDesc; -import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodHandleDesc; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import javax.lang.model.element.Element; - -import javax.lang.model.type.TypeMirror; - -import org.microbean.attributes.Attributed; -import org.microbean.attributes.Attributes; - -import org.microbean.constant.Constables; - -import static java.lang.constant.ConstantDescs.BSM_INVOKE; -import static java.lang.constant.ConstantDescs.CD_List; - -/** - * A pairing of an {@link Element} with a {@link List} of {@link Attributes}s. - * - * @param element an {@link Element} - * - * @param attributes a {@link List} of {@link Attributes}s - * - * @author Laird Nelson - */ -public final record AttributedElement(Element element, List attributes) implements Attributed, Constable { - - /** - * Creates a new {@link AttributedElement}. - * - * @param element a {@link Element}; must not be {@code null} - * - * @param attributes a {@link List} of {@link Attributes}; must not be {@code null} - * - * @exception NullPointerException if either argument is {@code null} - */ - public AttributedElement { - Objects.requireNonNull(element, "element"); - attributes = List.copyOf(attributes); - } - - /** - * Returns this {@link AttributedElement}'s {@linkplain Element#asType() type}. - * - * @return this {@link AttributedElement}'s {@linkplain Element#asType() type}; never {@code null} - */ - public final TypeMirror type() { - return this.element().asType(); - } - - /** - * Returns this {@link AttributedElement}'s {@link AttributedType}. - * - * @return this {@link AttributedElement}'s {@link AttributedType}; never {@code null} - * - * @see AttributedType - */ - public final AttributedType attributedType() { - return new AttributedType(this.type(), this.attributes()); - } - - /** - * Returns an {@link Optional} containing a {@link ConstantDesc} describing this {@link AttributedType}, or an - * {@linkplain Optional#isEmpty() empty Optional} if it could not be described. - * - * @return an {@link Optional} containing a {@link ConstantDesc} describing this {@link AttributedType}, or an - * {@linkplain Optional#isEmpty() empty Optional} if it could not be describe; never {@code null} - */ - @Override // Constable - public Optional describeConstable() { - return this.element() instanceof Constable e ? e.describeConstable() : Optional.empty() - .flatMap(elementDesc -> Constables.describeConstable(this.attributes()) - .map(attributesDesc -> DynamicConstantDesc.of(BSM_INVOKE, - MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName()), - ClassDesc.of("javax.lang.model.element.Element"), - CD_List), - elementDesc, - attributesDesc))); - } - -} diff --git a/src/main/java/org/microbean/bean/AttributedType.java b/src/main/java/org/microbean/bean/AttributedType.java deleted file mode 100644 index 7263f95..0000000 --- a/src/main/java/org/microbean/bean/AttributedType.java +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.lang.constant.ClassDesc; -import java.lang.constant.Constable; -import java.lang.constant.ConstantDesc; -import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodHandleDesc; - -import java.util.List; -import java.util.Optional; - -import javax.lang.model.type.TypeMirror; - -import org.microbean.attributes.Attributed; -import org.microbean.attributes.Attributes; - -import org.microbean.constant.Constables; - -import static java.lang.constant.ConstantDescs.BSM_INVOKE; -import static java.lang.constant.ConstantDescs.CD_List; -import static java.util.Arrays.asList; - -/** - * A pairing of a {@link TypeMirror} with a {@link List} of {@link Attributes}s. - * - * @param type a {@link TypeMirror} - * - * @param attributes a {@link List} of {@link Attributes}s - * - * @author Laird Nelson - */ -public final record AttributedType(TypeMirror type, List attributes) implements Attributed, Constable { - - /** - * Creates a new {@link AttributedType}. - * - * @param type a {@link TypeMirror}; must not be {@code null}; must be a {@linkplain - * javax.lang.model.type.TypeKind#isPrimitive() primitive}, {@linkplain javax.lang.model.type.TypeKind#ARRAY array} or - * {@linkplain javax.lang.model.type.TypeKind#DECLARED declared} type - * - * @param attributes an array of {@link Attributes}; may be {@code null} - * - * @exception NullPointerException if {@code type} is {@code null} - * - * @exception IllegalArgumentException if {@code type} is the wrong kind of type - */ - public AttributedType(final TypeMirror type, final Attributes... attributes) { - this(type, attributes == null || attributes.length <= 0 ? List.of() : asList(attributes)); - } - - /** - * Creates a new {@link AttributedType}. - * - * @param type a {@link TypeMirror}; must not be {@code null}; must be a {@linkplain - * javax.lang.model.type.TypeKind#isPrimitive() primitive}, {@linkplain javax.lang.model.type.TypeKind#ARRAY array} or - * {@linkplain javax.lang.model.type.TypeKind#DECLARED declared} type - * - * @param attributes a {@link List} of {@link Attributes}; must not be {@code null} - * - * @exception NullPointerException if either argument is {@code null} - * - * @exception IllegalArgumentException if {@code type} is the wrong kind of type - */ - public AttributedType { - switch (type.getKind()) { - case ARRAY, BOOLEAN, BYTE, CHAR, DECLARED, DOUBLE, FLOAT, INT, LONG, SHORT: - break; - case ERROR, EXECUTABLE, INTERSECTION, MODULE, NONE, NULL, OTHER, PACKAGE, TYPEVAR, UNION, VOID, WILDCARD: - default: - throw new IllegalArgumentException("type: " + type); - } - attributes = List.copyOf(attributes); - } - - /** - * Creates a new {@link AttributedType}. - * - * @param type a {@link TypeMirror}; must not be {@code null}; must be a {@linkplain - * javax.lang.model.type.TypeKind#isPrimitive() primitive}, {@linkplain javax.lang.model.type.TypeKind#ARRAY array} or - * {@linkplain javax.lang.model.type.TypeKind#DECLARED declared} type - * - * @exception NullPointerException if {@code type} is {@code null} - * - * @exception IllegalArgumentException if {@code type} is the wrong kind of type - */ - public AttributedType(final TypeMirror type) { - this(type, List.of()); - } - - /** - * Returns an {@link Optional} containing a {@link ConstantDesc} describing this {@link AttributedType}, or an - * {@linkplain Optional#isEmpty() empty Optional} if it could not be described. - * - * @return an {@link Optional} containing a {@link ConstantDesc} describing this {@link AttributedType}, or an - * {@linkplain Optional#isEmpty() empty Optional} if it could not be describe; never {@code null} - */ - @Override // Constable - public Optional describeConstable() { - return this.type() instanceof Constable t ? t.describeConstable() : Optional.empty() - .flatMap(typeDesc -> Constables.describeConstable(this.attributes()) - .map(attributesDesc -> DynamicConstantDesc.of(BSM_INVOKE, - MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName()), - ClassDesc.of(TypeMirror.class.getName()), - CD_List), - typeDesc, - attributesDesc))); - } - - /** - * Returns an {@link AttributedType} comprising the supplied arguments. - * - * @param type a {@link TypeMirror}; must not be {@code null}; must be a {@linkplain - * javax.lang.model.type.TypeKind#isPrimitive() primitive}, {@linkplain javax.lang.model.type.TypeKind#ARRAY array} or - * {@linkplain javax.lang.model.type.TypeKind#DECLARED declared} type - * - * @param attributes an array of {@link Attributes}; may be {@code null} - * - * @return a non-{@code null} {@link AttributedType} - * - * @exception NullPointerException if {@code type} is {@code null} - * - * @exception IllegalArgumentException if {@code type} is the wrong kind of type - */ - public static final AttributedType of(final TypeMirror type, Attributes... attributes) { - return new AttributedType(type, attributes == null || attributes.length <= 0 ? List.of() : asList(attributes)); - } - -} diff --git a/src/main/java/org/microbean/bean/Bean.java b/src/main/java/org/microbean/bean/Bean.java index 171570f..9bbfb5c 100644 --- a/src/main/java/org/microbean/bean/Bean.java +++ b/src/main/java/org/microbean/bean/Bean.java @@ -25,6 +25,11 @@ import java.util.function.Function; +import org.microbean.assign.Aggregate; +import org.microbean.assign.Assignment; +import org.microbean.assign.AttributedElement; +import org.microbean.assign.AttributedType; + import static java.lang.constant.ConstantDescs.BSM_INVOKE; /** diff --git a/src/main/java/org/microbean/bean/BeanReduction.java b/src/main/java/org/microbean/bean/BeanReduction.java deleted file mode 100644 index 35d5d60..0000000 --- a/src/main/java/org/microbean/bean/BeanReduction.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.Objects; - -/** - * A pairing of an {@link AttributedType} and a {@link Bean} resulting from a reduction. - * - * @param the type of contextual instances the supplied {@link Bean} is capable of creating - * - * @param attributedType an {@link AttributedType} - * - * @param bean a {@link Bean} deemed suitable for the {@code attributedType} - * - * @author Laird Nelson - * - * @deprecated This class seems not to be needed so is tentatively deprecated. - */ -@Deprecated(since = "0.0.18") -public final record BeanReduction(AttributedType attributedType, Bean bean) { - - /** - * Creates a new {@link BeanReduction}. - * - * @param attributedType an {@link AttributedType}; must not be {@code null} - * - * @param bean a {@link Bean} deemed suitable for the {@code attributedType}; must not be {@code null} - */ - public BeanReduction { - Objects.requireNonNull(attributedType, "attributedType"); - Objects.requireNonNull(bean, "bean"); - } - -} diff --git a/src/main/java/org/microbean/bean/Creation.java b/src/main/java/org/microbean/bean/Creation.java index 434f792..8bcb342 100644 --- a/src/main/java/org/microbean/bean/Creation.java +++ b/src/main/java/org/microbean/bean/Creation.java @@ -38,7 +38,7 @@ public interface Creation extends ReferencesSelector { /** * Returns the {@link Id} of the {@link Bean} {@linkplain Bean#factory() whose} {@link Factory}'s {@link - * Factory#create(Creation)} invocation is responsible for the existence of this {@link Creation}. + * Factory#create(Creation)} invocation was responsible for the existence of this {@link Creation}. * *

Implementations of this method may return {@code null}.

* diff --git a/src/main/java/org/microbean/bean/Factory.java b/src/main/java/org/microbean/bean/Factory.java index b743687..6323804 100644 --- a/src/main/java/org/microbean/bean/Factory.java +++ b/src/main/java/org/microbean/bean/Factory.java @@ -21,6 +21,8 @@ import java.util.Optional; +import org.microbean.assign.Aggregate; + import static java.lang.constant.ConstantDescs.BSM_INVOKE; /** diff --git a/src/main/java/org/microbean/bean/Id.java b/src/main/java/org/microbean/bean/Id.java index 0bf8db2..94aca55 100644 --- a/src/main/java/org/microbean/bean/Id.java +++ b/src/main/java/org/microbean/bean/Id.java @@ -13,9 +13,7 @@ */ package org.microbean.bean; -import java.lang.constant.ClassDesc; import java.lang.constant.Constable; -import java.lang.constant.ConstantDesc; import java.lang.constant.DynamicConstantDesc; import java.lang.constant.MethodHandleDesc; diff --git a/src/main/java/org/microbean/bean/IdMatcher.java b/src/main/java/org/microbean/bean/IdMatcher.java index a7a70da..792b62f 100644 --- a/src/main/java/org/microbean/bean/IdMatcher.java +++ b/src/main/java/org/microbean/bean/IdMatcher.java @@ -18,6 +18,7 @@ import javax.lang.model.type.TypeMirror; +import org.microbean.assign.AttributedType; import org.microbean.assign.Matcher; import org.microbean.attributes.Attributes; @@ -31,38 +32,53 @@ * * @see BeanQualifiersMatcher * - * @see InterceptorBindingsMatcher - * * @see BeanTypeMatcher * + * @see Matcher + * * @see Id */ public final class IdMatcher implements Matcher { - private final BeanQualifiersMatcher qm; + private final BeanTypeMatcher tm; - private final InterceptorBindingsMatcher ibm; + private final BeanQualifiersMatcher qm; - private final BeanTypeMatcher tm; + private final Matcher other; /** * Creates a new {@link IdMatcher}. * + * @param tm a {@link BeanTypeMatcher}; must not be {@code null} + * * @param qm a {@link BeanQualifiersMatcher}; must not be {@code null} * - * @param ibm an {@link InterceptorBindingsMatcher}; must not be {@code null} + * @exception NullPointerException} if {@code tm} or {@code qm} is {@code null} + * + * @see #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, Matcher) + */ + public IdMatcher(final BeanTypeMatcher tm, final BeanQualifiersMatcher qm) { + this(tm, qm, null); + } + + /** + * Creates a new {@link IdMatcher}. * * @param tm a {@link BeanTypeMatcher}; must not be {@code null} * - * @exception NullPointerException} if any argument is {@code null} + * @param qm a {@link BeanQualifiersMatcher}; must not be {@code null} + * + * @param other a supplementary {@link Matcher}; may be {@code null} + * + * @exception NullPointerException} if {@code tm} or {@code qm} is {@code null} */ - public IdMatcher(final BeanQualifiersMatcher qm, - final InterceptorBindingsMatcher ibm, - final BeanTypeMatcher tm) { + public IdMatcher(final BeanTypeMatcher tm, + final BeanQualifiersMatcher qm, + final Matcher other) { super(); - this.qm = Objects.requireNonNull(qm, "qm"); - this.ibm = Objects.requireNonNull(ibm, "ibm"); this.tm = Objects.requireNonNull(tm, "tm"); + this.qm = Objects.requireNonNull(qm, "qm"); + this.other = other == null ? (t, i) -> true : other; } /** @@ -75,16 +91,14 @@ public IdMatcher(final BeanQualifiersMatcher qm, *
    * *
  1. An invocation of the {@link BeanQualifiersMatcher#test(Collection, Collection)} method on the {@link - * BeanQualifiersMatcher} supplied at {@linkplain #IdMatcher(BeanQualifiersMatcher, InterceptorBindingsMatcher, - * BeanTypeMatcher) construction time} supplied with the supplied {@linkplain AttributedType#attributes() + * BeanQualifiersMatcher} supplied at {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, + * Matcher) construction time} supplied with the supplied {@linkplain AttributedType#attributes() * AttributedType's attributes} and the supplied {@linkplain Id#attributes() Id's * attributes} returns {@code true}
  2. * - *
  3. An invocation of the {@link InterceptorBindingsMatcher#test(Collection, Collection)} method on the {@link - * BeanQualifiersMatcher} supplied at {@linkplain #IdMatcher(BeanQualifiersMatcher, InterceptorBindingsMatcher, - * BeanTypeMatcher) construction time} supplied with the supplied {@linkplain AttributedType#attributes() - * AttributedType's attributes} and the supplied {@linkplain Id#attributes() Id's - * attributes} returns {@code true}
  4. + *
  5. An invocation of the {@link Matcher#test(Object, Object)} method on the supplementary {@link Matcher} supplied + * at {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, Matcher) construction time} supplied with the + * supplied {@linkplain AttributedType} and the supplied {@link Id} returns {@code true}
  6. * *
  7. An invocation of this {@link IdMatcher}'s {@link #test(TypeMirror, Iterable)} method supplied with the supplied * {@linkplain AttributedType#type() AttributedType's type} and the supplied {@linkplain Id#attributes() @@ -102,20 +116,16 @@ public IdMatcher(final BeanQualifiersMatcher qm, * * @see BeanQualifiersMatcher#test(Collection, Collection) * - * @see InterceptorBindingsMatcher#test(Collection, Collection) - * * @see #test(TypeMirror, Iterable) * * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) */ @Override // Matcher (BiPredicate) public final boolean test(final AttributedType t, final Id id) { - final Collection attributes = t.attributes(); - final Collection idAttributes = id.attributes(); return - this.qm.test(attributes, idAttributes) && - this.ibm.test(attributes, idAttributes) && - this.test(t.type(), id.types()); + this.test(t.type(), id.types()) && + this.qm.test(t.attributes(), id.attributes()) && + this.other.test(t, id); } /** @@ -124,7 +134,7 @@ public final boolean test(final AttributedType t, final Id id) { * *

    A {@link TypeMirror} t from the supplied {@link Iterable} matches the supplied {@code type} * argument if an invocation of the {@link BeanTypeMatcher#test(TypeMirror, TypeMirror)} method invoked on the - * {@linkplain #IdMatcher(BeanQualifiersMatcher, InterceptorBindingsMatcher, BeanTypeMatcher) + * {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, InterceptorBindingsMatcher) * BeanTypeManager supplied at construction time} supplied with {@code type} and t returns * {@code true}.

    * @@ -138,7 +148,7 @@ public final boolean test(final AttributedType t, final Id id) { * * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) */ - public final boolean test(final TypeMirror type, final Iterable ts) { + private final boolean test(final TypeMirror type, final Iterable ts) { Objects.requireNonNull(type, "type"); for (final TypeMirror t : ts) { if (this.tm.test(type, t)) { diff --git a/src/main/java/org/microbean/bean/InterceptorBindings.java b/src/main/java/org/microbean/bean/InterceptorBindings.java deleted file mode 100644 index 5edab06..0000000 --- a/src/main/java/org/microbean/bean/InterceptorBindings.java +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2023–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import org.microbean.attributes.Attributes; -import org.microbean.attributes.StringValue; - -/** - * A utility class providing methods that work with interceptor bindings. - * - * @author Laird Nelson - */ -public final class InterceptorBindings { - - private static final Attributes INTERCEPTOR_BINDING = Attributes.of("InterceptorBinding"); - - private static final List INTERCEPTOR_BINDING_LIST = List.of(INTERCEPTOR_BINDING); - - private static final Attributes ANY_INTERCEPTOR_BINDING = Attributes.of("Any", INTERCEPTOR_BINDING_LIST); - - private InterceptorBindings() { - super(); - } - - /** - * Returns a {@link Attributes} representing the any interceptor binding. - * - * @return a {@link Attributes} representing the any interceptor binding; never {@code null} - */ - public static final Attributes anyInterceptorBinding() { - return ANY_INTERCEPTOR_BINDING; - } - - /** - * Returns {@code true} if and only if the supplied {@link Attributes} represents the any - * interceptor binding. - * - * @param a a {@link Attributes}; may be {@code null} in which case {@code false} will be returned - * - * @return {@code true} if and only if the supplied {@link Attributes} represents the any - * interceptor binding - * - * @see #anyInterceptorBinding() - */ - public static final boolean anyInterceptorBinding(final Attributes a) { - return ANY_INTERCEPTOR_BINDING.equals(a) && interceptorBinding(a); - } - - /** - * Returns a {@link Attributes} representing the interceptor binding (meta-) interceptor binding. - * - * @return a {@link Attributes} representing the interceptor binding (meta-) interceptor binding; - * never {@code null} - */ - public static final Attributes interceptorBinding() { - return INTERCEPTOR_BINDING; - } - - /** - * Returns {@code true} if and only if the supplied {@link Attributes} is itself a {@link Attributes} that can be used - * to designate other {@link Attributes} instances as interceptor bindings, or a {@link Attributes} so designated. - * - * @param a a {@link Attributes}; may be {@code null} in which case {@code false} will be returned - * - * @return {@code true} if and only if the supplied {@link Attributes} is itself a {@link Attributes} - * that can be used to designate other {@link Attributes} instances as interceptor bindings, or a {@link - * Attributes} so designated - * - * @see #interceptorBinding() - */ - public static final boolean interceptorBinding(final Attributes a) { - return a != null && interceptorBinding(a.attributes(a.name())); - } - - private static final boolean interceptorBinding(final Iterable mds) { - for (final Attributes md : mds) { - if (md.equals(INTERCEPTOR_BINDING) && md.attributes().isEmpty() || interceptorBinding(md)) { - return true; - } - } - return false; - } - - /** - * Given a {@link Collection} of {@link Attributes}s, returns an immutable {@link List} consisting of those - * {@link Attributes} instances that are {@linkplain #interceptorBinding() deemed to be interceptor bindings}. - * - * @param c a {@link Collection}; must not be {@code null} - * - * @return a {@link List} of interceptor bindings - * - * @exception NullPointerException if {@code c} is {@code null} - */ - public static final List interceptorBindings(final Collection c) { - if (c.isEmpty()) { - return List.of(); - } - final ArrayList list = new ArrayList<>(c.size()); - for (final Attributes a : c) { - if (interceptorBinding(a)) { - list.add(a); - } - } - list.trimToSize(); - return Collections.unmodifiableList(list); - } - - /** - * Returns a {@link Attributes} representing a target class interceptor binding. - * - * @param type the target class name; must not be {@code null} - * - * @return a {@link Attributes} representing a target class interceptor binding; never {@code null} - * - * @exception NullPointerException if {@code type} is {@code null} - */ - public static final Attributes targetClassInterceptorBinding(final String type) { - return Attributes.of("TargetClass", Map.of("class", StringValue.of(type)), Map.of(), Map.of("TargetClass", INTERCEPTOR_BINDING_LIST)); - } - - /** - * Returns {@code true} if and only if the supplied {@link Attributes} is a target class interceptor - * binding. - * - * @param a a {@link Attributes}; must not be {@code null} - * - * @return {@code true} if and only if the supplied {@link Attributes} is a target class interceptor - * binding - * - * @exception NullPointerException if {@code a} is {@code null} - */ - // Is a a TargetClass interceptor binding? - public static final boolean targetClassInterceptorBinding(final Attributes a) { - return a.name().equals("TargetClass") && interceptorBinding(a); - } - -} diff --git a/src/main/java/org/microbean/bean/InterceptorBindingsMatcher.java b/src/main/java/org/microbean/bean/InterceptorBindingsMatcher.java deleted file mode 100644 index 55dd510..0000000 --- a/src/main/java/org/microbean/bean/InterceptorBindingsMatcher.java +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.Collection; -import java.util.List; - -import org.microbean.assign.Matcher; - -import org.microbean.attributes.Attributes; - -import static org.microbean.bean.InterceptorBindings.anyInterceptorBinding; - -/** - * A {@link Matcher} encapsulating CDI-compatible interceptor binding - * matching rules. - * - * @author Laird Nelson - * - * @see #test(Collection, Collection) - */ -public class InterceptorBindingsMatcher implements Matcher, Collection> { - - /** - * Creates a new {@link InterceptorBindingsMatcher}. - */ - public InterceptorBindingsMatcher() { - super(); - } - - /** - * Returns {@code true} if and only if either (a) both the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and - * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in - * {@code payloadAttributes} are {@linkplain Collection#isEmpty() empty}, or (b) if the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} has - * only one element and that element {@linkplain InterceptorBindings#anyInterceptorBinding(Attributes) is the - * any interceptor binding}, or (c) the sizes of the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and - * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in - * {@code payloadAttributes} are the same and the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} - * {@linkplain Collection#containsAll(Collection) contains all} the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} and - * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in - * {@code payloadAttributes} {@linkplain Collection#containsAll(Collection) contains all} the collection of - * {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code - * receiverAttributes}. - * - * @param receiverAttributes a {@link Collection} of {@link Attributes}s; must not be {@code null} - * - * @param payloadAttributes a {@link Collection} of {@link Attributes}s; must not be {@code null} - * - * @return {@code true} if and only if either (a) both the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and - * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in - * {@code payloadAttributes} are {@linkplain Collection#isEmpty() empty}, or (b) if the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} has - * only one element and that element {@linkplain InterceptorBindings#anyInterceptorBinding(Attributes) is the - * any interceptor binding}, or (c) the sizes of the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} and - * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in - * {@code payloadAttributes} are the same and the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code receiverAttributes} - * {@linkplain Collection#containsAll(Collection) contains all} the collection of {@linkplain - * InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code payloadAttributes} and - * the collection of {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in - * {@code payloadAttributes} {@linkplain Collection#containsAll(Collection) contains all} the collection of - * {@linkplain InterceptorBindings#interceptorBindings(Collection) interceptor bindings present} in {@code - * receiverAttributes} - * - * @exception NullPointerException if either {@code receiverAttributes} or {@code payloadAttributes} is {@code null} - */ - @Override // Matcher, Collection> - public final boolean test(final Collection receiverAttributes, - final Collection payloadAttributes) { - final Collection payloadBindings = interceptorBindings(payloadAttributes); - if (payloadBindings.isEmpty()) { - return interceptorBindings(receiverAttributes).isEmpty(); - } else if (payloadBindings.size() == 1 && anyInterceptorBinding(payloadBindings.iterator().next())) { - return true; - } - final Collection receiverBindings = interceptorBindings(receiverAttributes); - return - receiverBindings.size() == payloadBindings.size() && - receiverBindings.containsAll(payloadBindings) && - payloadBindings.containsAll(receiverBindings); - } - - /** - * Given a {@link Collection} of {@link Attributes}s, returns an immutable {@link Collection} consisting of those - * {@link Attributes} instances that are deemed to be interceptor bindings. - * - *

    The default implementation of this method returns the value of an invocation of the {@link - * InterceptorBindings#interceptorBindings(Collection)} method.

    - * - * @param as a {@link Collection}; must not be {@code null} - * - * @return a {@link List} of interceptor bindings; never {@code null} - * - * @exception NullPointerException if {@code as} is {@code null} - */ - protected Collection interceptorBindings(final Collection as) { - return InterceptorBindings.interceptorBindings(as); - } - -} diff --git a/src/main/java/org/microbean/bean/Ranked.java b/src/main/java/org/microbean/bean/Ranked.java index 2df569e..8d76910 100644 --- a/src/main/java/org/microbean/bean/Ranked.java +++ b/src/main/java/org/microbean/bean/Ranked.java @@ -35,7 +35,10 @@ * @see #outranks(int) * * @see #outranks(int, int) + * + * @deprecated This class is deprecated for future removal. */ +@Deprecated public interface Ranked { diff --git a/src/main/java/org/microbean/bean/RankedReducer.java b/src/main/java/org/microbean/bean/RankedReducer.java deleted file mode 100644 index 4c84b0a..0000000 --- a/src/main/java/org/microbean/bean/RankedReducer.java +++ /dev/null @@ -1,185 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.ArrayList; -import java.util.List; - -import java.util.function.BiFunction; - -import static java.util.Collections.unmodifiableList; - -import static org.microbean.bean.Ranked.DEFAULT_RANK; - -/** - * A {@link Reducer} implementation that works with {@link Ranked} objects. - * - * @param the type of criteria used in the {@link #reduce(List, Object, BiFunction)} method - * - * @param a {@link Ranked} type - * - * @author Laird Nelson - * - * @see #reduce(List, Object, BiFunction) - * - * @deprecated This class is not really needed and is tentatively deprecated. - */ -@Deprecated(since = "0.0.18") -public final class RankedReducer implements Reducer { - - - /* - * Static fields. - */ - - - private static final RankedReducer INSTANCE = new RankedReducer<>(); - - - /* - * Constructors. - */ - - - private RankedReducer() { - super(); - } - - - /* - * Instance methods. - */ - - - @Override - public final T reduce(final List elements, - final C c, - final BiFunction, ? super C, ? extends T> failureHandler) { - if (elements == null || elements.isEmpty()) { - // https://github.com/microbean/microbean-bean/issues/21 - return failureHandler == null ? Reducer.fail(List.of(), c) : failureHandler.apply(List.of(), c); - } else if (elements.size() == 1) { - return elements.get(0); - } - - T candidate = null; - List unresolved = null; - // Highest rank wins - int maxRank = DEFAULT_RANK; - - for (final T element : elements) { - if (alternate(element)) { - final int elementRank = rank(element); - if (elementRank == maxRank) { - if (candidate == null || !alternate(candidate)) { - // Prefer elements regardless of ranks. - candidate = element; - } else { - assert rank(candidate) == maxRank : "Unexpected rank: " + rank(candidate) + "; was expecting: " + maxRank; - // The existing candidate is an alternate and by definition has the highest rank we've seen so far; the - // incoming element is also an alternate; both have equal ranks: we can't resolve this. - if (unresolved == null) { - unresolved = new ArrayList<>(6); - } - unresolved.add(candidate); - unresolved.add(element); - candidate = null; - } - } else if (elementRank > maxRank) { - if (candidate == null || !alternate(candidate) || elementRank > rank(candidate)) { - // The existing candidate is either null, not an alternate (and alternates are always preferred), or an - // alternate with losing rank, so junk it in favor of the incoming element. - candidate = element; - // We have a new maxRank. - maxRank = elementRank; - } else if (elementRank == rank(candidate)) { - // The existing candidate is also an alternate and has the same rank. - if (unresolved == null) { - unresolved = new ArrayList<>(6); - } - unresolved.add(candidate); - unresolved.add(element); - candidate = null; - } else { - assert elementRank < rank(candidate) : "elementRank >= rank(candidate): " + elementRank + " >= " + rank(candidate); - // The existing candidate is also an alternate but has a higher rank than the alternate, so keep it (do - // nothing). - } - } - // ...else drop element by doing nothing - } else if (candidate == null) { - // The incoming element is not an alternate, but that doesn't matter; the candidate is null, so accept the - // element no matter what. - candidate = element; - } else if (!alternate(candidate)) { - // The existing candidate is not an alternate. The incoming element is not an alternate. Ranks in this case are - // irrelevant, perhaps surprisingly. We cannot resolve this. - if (unresolved == null) { - unresolved = new ArrayList<>(6); - } - unresolved.add(candidate); - unresolved.add(element); - candidate = null; - } - // ...else do nothing - } - - if (unresolved != null && !unresolved.isEmpty()) { - if (candidate != null) { - unresolved.add(candidate); - } - candidate = - failureHandler == null ? Reducer.fail(unmodifiableList(unresolved), c) : failureHandler.apply(unmodifiableList(unresolved), c); - } - - return candidate; - } - - // Preparing for a future where alternate status is not a first-class citizen. - private final boolean alternate(final T t) { - return t.alternate(); - } - - // Preparing for a future where rank is not a first-class citizen. - private final int rank(final T t) { - return t.rank(); - } - - - /* - * Static methods. - */ - - - /** - * Returns a {@link RankedReducer} implementation. - * - * @param the type of criteria - * - * @param the type of the {@link Ranked} reduction - * - * @return a {@link RankedReducer} implementation; never {@code null} - * - * @microbean.nullability This method never returns {@code null}. - * - * @microbean.idempotency This method is idempotent and deterministic. - * - * @microbean.threadsafety This method is safe for concurrent use by multiple threads. - */ - @SuppressWarnings("unchecked") - public static final Reducer of() { - return (Reducer)INSTANCE; - } - -} diff --git a/src/main/java/org/microbean/bean/Reducer.java b/src/main/java/org/microbean/bean/Reducer.java deleted file mode 100644 index 958adc4..0000000 --- a/src/main/java/org/microbean/bean/Reducer.java +++ /dev/null @@ -1,295 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.List; - -import java.util.function.BiFunction; - -/** - * A {@linkplain FunctionalInterface functional interface} whose implementations can either reduce a supplied - * {@link List} of elements representing a successful selection to a single element normally drawn or - * calculated from the selection according to some criteria, or fail gracefully in the face of ambiguity by - * invoking a supplied failure handler. - * - *

    The reduction may be a simple filtering operation, or may be a summing or aggregating operation, or anything - * else.

    - * - *

    This interface is conceptually subordinate to, but should not be confused with, the {@link Reducible} - * interface.

    - * - *

    {@link Reducer} implementations are often used to help build {@link Reducible} implementations. See, for example, - * {@link Reducible#ofCaching(Selectable, Reducer, BiFunction)}.

    - * - * @param the type of criteria - * - * @param the element type - * - * @author Laird Nelson - * - * @see #reduce(List, Object, BiFunction) - * - * @see Reducible - * - * @deprecated This interface is not really needed and is tentatively deprecated. - */ -@Deprecated(since = "0.0.18") -@FunctionalInterface -public interface Reducer { - - /** - * Performs some kind of reductive or filtering operation on the supplied {@link List}, according to the supplied - * criteria, and returns the single result, or, if reduction fails, invokes the supplied {@link BiFunction} with a - * sublist representing a partial reduction (or an empty list representing a reduction that simply could not be - * performed), along with the supplied criteria, and returns its result. - * - *

    Implementations of this method must return determinate values.

    - * - * @param elements an immutable {@link List} to reduce; must not be {@code null}; represents a successful selection - * from a larger collection of elements - * - * @param c the criteria effectively describing the initial selection and the desired reduction; may be {@code null} - * to indicate no criteria; may be ignored if not needed by an implementation - * - * @param failureHandler a {@link BiFunction} receiving a failed reduction (usually a portion of the supplied {@code - * elements}), and the selection and reduction criteria, that returns a substitute reduction (or, more commonly, - * throws an exception); must not be {@code null}; must be invoked if reduction fails or undefined behavior may result - * - * @return a single, possibly {@code null}, element normally drawn or computed from the supplied {@code elements}, or - * a synthetic value returned by an invocation of the supplied {@code failureHandler}'s {@link - * BiFunction#apply(Object, Object) apply(Object, Object)} method - * - * @exception NullPointerException if {@code elements} or {@code failureHandler} is {@code null} - * - * @exception ReductionException if the {@code failureHandler} function throws a {@link ReductionException} - * - * @see #fail(List, Object) - */ - // List, not Stream, for equality semantics and caching purposes. - // List, not Set, because it's much faster and reduction can take care of duplicates if needed - // List, not Collection, because you want easy access to the (possibly) only element without creating iterators - // C, not Predicate, because it may not be necessary to actually filter the List to perform the reduction - // failureHandler will receive only those elements that could not be eliminated - // c is a pass-through used only during failure - public T reduce(final List elements, - final C c, - final BiFunction, ? super C, ? extends T> failureHandler); - - - /* - * Default methods. - */ - - - /** - * Invokes the {@link #reduce(List, Object, BiFunction)} method with the return value of an invocation of the {@link - * Selectable#select(Object) select(Object)} method on the supplied {@link Selectable} supplied with {@code c}, and - * the supplied {@code c} and {@code failureHandler} arguments, and returns the result. - * - * @param f a {@link Selectable}; must not be {@code null} - * - * @param c the criteria effectively describing the initial selection and the desired reduction; may be {@code null} - * to indicate no criteria; may be ignored if not needed by an implementation - * - * @param failureHandler a {@link BiFunction} receiving a failed reduction (usually a portion of the supplied {@code - * elements}), and the selection and reduction criteria, that returns a substitute reduction (or, more commonly, - * throws an exception); must not be {@code null}; must be invoked if reduction fails or undefined behavior may result - * - * @return a single, possibly {@code null}, element normally drawn or computed from the {@link List} returned from the - * supplied {@link Selectable}'s {@link Selectable#select(Object) select(Object)} method, or a synthetic value - * returned by an invocation of the supplied {@code failureHandler}'s {@link BiFunction#apply(Object, Object) - * apply(Object, Object)} method - * - * @exception NullPointerException if {@code f} or {@code failureHandler} is {@code null} - * - * @see #reduce(List, Object, BiFunction) - */ - public default T reduce(final Selectable f, - final C c, - final BiFunction, ? super C, ? extends T> failureHandler) { - return this.reduce(f.select(c), c, failureHandler); - } - - /** - * Invokes the {@link #reduce(List, Object, BiFunction)} method with the return value of an invocation of the {@link - * Selectable#select(Object) select(Object)} method on the supplied {@link Selectable} supplied with {@code c}, and - * the supplied {@code c} and a reference to the {@link #fail(List, Object) fail(List, Object)} method, and returns - * the result. - * - * @param f a {@link Selectable}; must not be {@code null} - * - * @param c the criteria effectively describing the initial selection and the desired reduction; may be {@code null} - * to indicate no criteria; may be ignored if not needed by an implementation - * - * @return a single, possibly {@code null}, element normally drawn or computed from the {@link List} returned from the - * supplied {@link Selectable}'s {@link Selectable#select(Object) select(Object)} method, or the sole element - * returned by an invocation of the {@link #fail(List, Object) fail(List, Object)} method - * - * @exception NullPointerException if {@code f} or {@code failureHandler} is {@code null} - * - * @exception UnsatisfiedReductionException if an invocation of the {@link #fail(List, Object) fail(List, Object)} method throws an {@link UnsatisfiedReductionException} - * - * @exception AmbiguousReductionException if an invocation of the {@link #fail(List, Object) fail(List, Object)} method throws an {@link AmbiguousReductionException} - * - * @see #reduce(Selectable, Object, BiFunction) - * - * @see #fail(List, Object) - */ - public default T reduce(final Selectable f, final C c) { - return this.reduce(f, c, Reducer::fail); - } - - /** - * Invokes the {@link #reduce(List, Object, BiFunction)} method with the supplied arguments and a reference to the - * {@link #fail(List, Object)} method, and returns the result. - * - * @param elements an immutable {@link List} to reduce; must not be {@code null}; represents a successful selection - * from a larger collection of elements - * - * @param c the criteria effectively describing the initial selection and the desired reduction; may be {@code null} - * to indicate no criteria; may be ignored if not needed by an implementation - * - * @return a single, possibly {@code null}, element normally drawn or computed from the supplied {@code elements}, or - * a synthetic value returned by an invocation of the supplied {@code failureHandler}'s {@link - * BiFunction#apply(Object, Object) apply(Object, Object)} method - * - * @exception NullPointerException if {@code elements} is {@code null} - * - * @see #fail(List, Object) - * - * @see #reduce(List, Object, BiFunction) - */ - public default T reduce(final List elements, final C c) { - return this.reduce(elements, c, Reducer::fail); - } - - - /* - * Static methods. - */ - - - /** - * Returns a {@link Reducer} whose {@link #reduce(List, Object, BiFunction)} method, for a given {@link List} of - * elements, returns the {@link List}'s sole element if the {@link List} has exactly one element, and returns the - * result of invoking its supplied failure handler otherwise. - * - * @param the type of the criteria - * - * @param the type of the elements - * - * @return a {@link Reducer}; never {@code null} - * - * @see #reduce(List, Object, BiFunction) - */ - // A Reducer that works only when the selection is of size 1. - public static Reducer ofSimple() { - return Reducer::reduceObviously; - } - - /** - * Returns a {@link Reducer} whose {@link #reduce(List, Object, BiFunction)} method, for a given {@link List} of - * elements, returns the result of invoking its supplied failure handler. - * - * @param the type of the criteria - * - * @param the type of the elements - * - * @return a {@link Reducer}; never {@code null} - * - * @see #reduce(List, Object, BiFunction) - */ - // A Reducer that simply calls its supplied failure handler no matter what. - public static Reducer ofFailing() { - return Reducer::failUnconditionally; - } - - /** - * Throws an {@link UnsatisfiedReductionException} if {@code elements} is empty, throws an {@link - * AmbiguousReductionException} if the {@linkplain List#size() size} of {@code elements} is greater than {@code 1}, - * and returns the sole element of {@code elements} otherwise. - * - *

    A reference to this method is often used as a failure handler in an invocation of the {@link - * #reduce(List, Object, BiFunction)} method.

    - * - * @param the type of the criteria - * - * @param the type of the elements - * - * @param elements a {@link List} of elements under reduction; must not be {@code null} - * - * @param c a criteria object; may be {@code null} - * - * @return the sole element present in {@code elements}, which may be {@code null} - * - * @exception NullPointerException if {@code elements} is {@code null} - * - * @exception UnsatisfiedReductionException if {@code elements} is empty - * - * @exception AmbiguousReductionException if the {@linkplain List#size() size} of {@code elements} is greater than - * {@code 1} - * - * @see #reduce(List, Object, BiFunction) - * - * @see #reduce(List, Object) - */ - // Default failure handler; call by method reference. Fails if the selection does not consist of one element. - public static T fail(final List elements, final C c) { - return switch (elements.size()) { - case 0 -> throw new UnsatisfiedReductionException((Object)c, null, null); - case 1 -> elements.get(0); - default -> throw new AmbiguousReductionException(c, elements, "Cannot reduce: " + elements); - }; - } - - /** - * Returns {@code null} when invoked, regardless of arguments. - * - *

    A reference to this method can be used as a failure handler in an invocation of the {@link - * #reduce(List, Object, BiFunction)} method.

    - * - * @param the type of the first parameter; ignored - * - * @param the type of the second parameter; ignored - * - * @param the type of the return type; ignored - * - * @param a an object; may be {@code null}; ignored - * - * @param b an object; may be {@code null}; ignored - * - * @return {@code null} when invoked - */ - // Convenience failure handler; call by method reference. Returns null when invoked. - public static C returnNull(final A a, final B b) { - return null; - } - - private static T reduceObviously(final List l, - final C c, - final BiFunction, ? super C, ? extends T> fh) { - return switch (l.size()) { - case 0 -> fh == null ? fail(List.of(), c) : fh.apply(List.of(), c); - case 1 -> l.get(0); - default -> fh == null ? fail(l, c) : fh.apply(l, c); - }; - } - - private static T failUnconditionally(final List l, - final C c, - final BiFunction, ? super C, ? extends T> fh) { - return fh.apply(l, c); - } - -} diff --git a/src/main/java/org/microbean/bean/Reducible.java b/src/main/java/org/microbean/bean/Reducible.java deleted file mode 100644 index 3df5f6e..0000000 --- a/src/main/java/org/microbean/bean/Reducible.java +++ /dev/null @@ -1,215 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.List; -import java.util.Objects; - -import java.util.concurrent.ConcurrentHashMap; - -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * A {@linkplain FunctionalInterface functional interface} whose implementations can reduce an unspecified - * notional collection of elements to a single element according to some criteria. - * - *

    This interface is related to, but should not be confused with, the {@link Reducer} interface, implementations of - * which can be used to build {@link Reducible} instances.

    - * - * @param the type of criteria - * - * @param the element type - * - * @author
    Laird Nelson - * - * @see #reduce(Object) - * - * @see Reducer - * - * @deprecated This interface is not really needed and is tentatively deprecated. - */ -@Deprecated(since = "0.0.18") -@FunctionalInterface -public interface Reducible { - - - /* - * Instance methods. - */ - - - /** - * Given a criteria object, which may be {@code null}, returns an object that represents the reduction of a - * notional collection of objects. - * - *

    Most {@link Reducible} implementations will return determinate values from invocations of this method, but there - * is no requirement to do so.

    - * - * @param criteria the criteria; may be {@code null} to indicate no criteria - * - * @return a single object, or {@code null} - * - * @exception ReductionException if reduction could not occur or if an error occurs - */ - public T reduce(final C criteria); - - - /* - * Static methods. - */ - - - /** - * Calls the {@link #of(Selectable, Reducer, BiFunction)} method with the supplied {@code selectable}, the supplied {@code r}, and a reference to the {@link Reducer#fail(List, Object)} method, - * and returns the result. - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @param r a {@link Reducer}; must not be {@code null} - * - * @return a {@link Reducible}; never {@code null} - * - * @exception NullPointerException if {@code selectable} or {@code r} is {@code null} - * - * @see #of(Selectable, Reducer, BiFunction) - * - * @see Reducer#fail(List, Object) - */ - public static Reducible of(final Selectable selectable, - final Reducer r) { - return of(selectable, r, Reducer::fail); - } - - /** - * Returns a {@link Reducible} implementation that uses the supplied {@link Reducer} for its reduction operations. - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @param r a {@link Reducer}; must not be {@code null} - * - * @param failureHandler a {@link BiFunction} serving as the supplied {@link Reducer}'s failure handler; - * must not be {@code null} - * - * @return a {@link Reducible}; never {@code null} - * - * @exception NullPointerException if any argument is {@code null} - * - * @see Reducer - */ - public static Reducible of(final Selectable selectable, - final Reducer r, - final BiFunction, ? super C, ? extends E> failureHandler) { - Objects.requireNonNull(selectable, "selectable"); - Objects.requireNonNull(r, "r"); - final BiFunction, ? super C, ? extends E> fh = Objects.requireNonNull(failureHandler, "failureHandler"); - return c -> r.reduce(selectable.select(c), c, fh); - } - - /** - * Calls the {@link #ofCaching(Selectable, Reducer, BiFunction)} method with the supplied {@code selectable}, the - * supplied {@code r}, the supplied {@code failureHandler}, and a reference to the {@link Reducer#fail(List, Object)} - * method, and returns its result. - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @param r a {@link Reducer}; must not be {@code null} - * - * @return a {@link Reducible}; never {@code null} - * - * @exception NullPointerException if any argument is {@code null} - * - * @see #ofCaching(Selectable, Reducer, BiFunction) - */ - public static Reducible ofCaching(final Selectable selectable, final Reducer r) { - return ofCaching(selectable, r, Reducer::fail); - } - - /** - * Calls the {@link #ofCaching(Selectable, Reducer, BiFunction, BiFunction)} method with the supplied {@code - * selectable}, the supplied {@code r}, the supplied {@code fh}, and a reference to the {@link - * ConcurrentHashMap#computeIfAbsent(Object, java.util.function.Function) computeIfAbsent(Object, Function)} method of - * a new {@link ConcurrentHashMap}, and returns its result. - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @param r a {@link Reducer}; must not be {@code null} - * - * @param fh a {@link BiFunction} serving as the supplied {@link Reducer}'s failure handler; - * must not be {@code null} - * - * @return a {@link Reducible}; never {@code null} - * - * @exception NullPointerException if any argument is {@code null} - * - * @see #ofCaching(Selectable, Reducer, BiFunction, BiFunction) - */ - public static Reducible ofCaching(final Selectable selectable, - final Reducer r, - final BiFunction, ? super C, ? extends E> fh) { - return ofCaching(selectable, r, fh, new ConcurrentHashMap()::computeIfAbsent); - } - - /** - * Returns a {@link Reducible} implementation that uses the supplied {@link Reducer} for its reduction operations and - * the supplied {@code computeIfAbsent} {@link BiFunction} for its caching implementation. - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @param r a {@link Reducer}; must not be {@code null} - * - * @param fh a {@link BiFunction} serving as the supplied {@link Reducer}'s failure handler; must not be - * {@code null} - * - * @param cache a {@link BiFunction} with the same semantics as the {@link - * java.util.Map#computeIfAbsent(Object, java.util.function.Function)} method; must not be {@code null} - * - * @return a {@link Reducible}; never {@code null} - * - * @exception NullPointerException if any argument is {@code null} - * - * @see #of(Selectable, Reducer, BiFunction) - * - * @see java.util.Map#computeIfAbsent(Object, java.util.function.Function) - */ - public static Reducible ofCaching(final Selectable selectable, - final Reducer r, - final BiFunction, ? super C, ? extends E> fh, - final BiFunction, ? extends E> cache) { - Objects.requireNonNull(cache, "cache"); - final Reducible reducible = of(selectable, r, fh); - return c -> cache.apply(c, reducible::reduce); - } - -} diff --git a/src/main/java/org/microbean/bean/ReductionException.java b/src/main/java/org/microbean/bean/ReductionException.java index 71757fa..c1e390a 100644 --- a/src/main/java/org/microbean/bean/ReductionException.java +++ b/src/main/java/org/microbean/bean/ReductionException.java @@ -17,10 +17,6 @@ * A {@link BeanException} concerning problematic reductions. * * @author Laird Nelson - * - * @see Reducible - * - * @see Reducer */ public sealed class ReductionException extends BeanException permits AmbiguousReductionException, UnsatisfiedReductionException { diff --git a/src/main/java/org/microbean/bean/References.java b/src/main/java/org/microbean/bean/References.java index 9f59e4a..a71f319 100644 --- a/src/main/java/org/microbean/bean/References.java +++ b/src/main/java/org/microbean/bean/References.java @@ -25,6 +25,7 @@ * * @see ReferencesSelector */ +// TODO: not crazy about the circular dependencies, but they're no worse than, say, a sealed class public interface References extends Iterable, ReferencesSelector { /** @@ -49,17 +50,6 @@ public default R get() { return r; } - /** - * Destroys the supplied contextual reference if and only if it meets the conditions for destruction. - * - * @param r a contextual reference; may be {@code null} in which case {@code false} will be returned - * - * @return {@code true} if and only if destruction occurred - * - * @exception DestructionException if an error occurs - */ - public boolean destroy(final R r); // e.g. CDI's Instances#destroy(Object); works only on @Dependent objects - /** * Returns the size of this {@link References}. * diff --git a/src/main/java/org/microbean/bean/ReferencesSelector.java b/src/main/java/org/microbean/bean/ReferencesSelector.java index a71e738..cb757da 100644 --- a/src/main/java/org/microbean/bean/ReferencesSelector.java +++ b/src/main/java/org/microbean/bean/ReferencesSelector.java @@ -13,6 +13,8 @@ */ package org.microbean.bean; +import org.microbean.assign.AttributedType; + /** * A supplier of {@link References} objects. * @@ -24,8 +26,20 @@ * * @see References */ +// TODO: not crazy about the circular dependencies, but they're no worse than, say, a sealed class public interface ReferencesSelector { + /** + * Destroys the supplied contextual reference if and only if it meets the conditions for destruction. + * + * @param r a contextual reference; may be {@code null} in which case {@code false} will be returned + * + * @return {@code true} if and only if destruction occurred + * + * @exception DestructionException if an error occurs + */ + public boolean destroy(final Object r); // e.g. CDI's Instance#destroy(Object); works only on normal- and @Dependent-scoped objects + /** * Returns a {@link References} capable of locating contextual references of the relevant type. * @@ -42,7 +56,8 @@ public interface ReferencesSelector { public References references(final AttributedType t); /** - * Returns the sole contextual reference of the relevant type. + * A convenience method that acquires and returns what is presumed, possibly incorrectly, to be the sole contextual + * reference of the relevant type. * * @param the contextual reference type * @@ -55,6 +70,10 @@ public interface ReferencesSelector { * @exception UnsatisfiedReductionException if there is no contextual reference for the relevant type * * @exception AmbiguousReductionException if there is more than one contextual reference for the relevant type + * + * @see #references(AttributedType) + * + * @see References#get() */ public default R reference(final AttributedType t) { return this.references(t).get(); diff --git a/src/main/java/org/microbean/bean/Selectable.java b/src/main/java/org/microbean/bean/Selectable.java deleted file mode 100644 index ad31a54..0000000 --- a/src/main/java/org/microbean/bean/Selectable.java +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024–2025 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.List; - -/** - * A notional list of elements from which immutable sublists may be selected according to some - * criteria. - * - * @param the criteria type - * - * @param the element type - * - * @author Laird Nelson - */ -@FunctionalInterface -public interface Selectable { - - /** - * Selects and returns an immutable {@link List} representing a sublist of this {@link Selectable}'s - * elements, as mediated by the supplied criteria. - * - *

    Implementations of this method must be idempotent and must return a determinate value.

    - * - *

    Implementations of this method must not return {@code null}.

    - * - *

    Implementations of this method should not call {@link #list()}, since that method is typically implemented in - * terms of this one, or undefined behavior may result.

    - * - * @param criteria the criteria to use; may be {@code null} - * - * @return an immutable sublist of this {@link Selectable}'s elements; never {@code null} - * - * @see #list() - */ - // Filters this thing according to the supplied criteria, producing a List. - // List not Stream to permit caching - // List not Collection so equals() is well-defined - // List is unmodifiable and is always valid for the supplied criteria (unenforceable) - // C and not Predicate because equality semantics for Predicate are not well-defined (caching again) - public List select(final C criteria); - - /** - * Returns an immutable {@link List} of all of this {@link Selectable}'s elements. - * - *

    Implementations of this method must be idempotent and must return a determinate value.

    - * - *

    Implementations of this method must not return {@code null}.

    - * - *

    The default implementation of this method calls the {@link #select(Object)} method with {@code null} as the sole - * argument.

    - * - * @return an immutable {@link List} of all of this {@link Selectable}'s elements; never {@code null} - * - * @see #select(Object) - */ - public default List list() { - return this.select(null); - } - -} diff --git a/src/main/java/org/microbean/bean/Selectables.java b/src/main/java/org/microbean/bean/Selectables.java index 799fd15..e533457 100644 --- a/src/main/java/org/microbean/bean/Selectables.java +++ b/src/main/java/org/microbean/bean/Selectables.java @@ -22,20 +22,25 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; +import java.util.function.BiPredicate; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.ToIntFunction; +import org.microbean.assign.AttributedType; import org.microbean.assign.Matcher; +import org.microbean.assign.Selectable; import static org.microbean.bean.Beans.normalize; -import static org.microbean.bean.Ranked.DEFAULT_RANK; - /** * Utility methods for working with {@link Selectable}s. * * @author Laird Nelson * * @see Selectable + * + * @see org.microbean.assign.Selectables */ public final class Selectables { @@ -60,9 +65,42 @@ private Selectables() { * @see Ranked#rank() * * @see Ranked#alternate() + * + * @see #ambiguityReducing(Selectable, Predicate, ToIntFunction) + * + * @deprecated Please use the {@link #ambiguityReducing(Selectable, Predicate, ToIntFunction)} method instead. */ + @Deprecated(forRemoval = true, since = "0.0.19") public static final Selectable ambiguityReducing(final Selectable s) { + return ambiguityReducing(s, Ranked::alternate, Ranked::rank); + } + + /** + * Returns a {@link Selectable} that reduces any ambiguity in the results returned by another {@link Selectable}, + * considering alternate status and rank. + * + * @param the criteria type + * + * @param the element type + * + * @param s a {@link Selectable}; must not be {@code null} + * + * @param p a {@link Predicate} that tests whether an element is an alternate; must not be {@code null} + * + * @param ranker a {@link ToIntFunction} that returns a rank for an alternate; a rank of {@code 0} + * indicates no particular rank; must not be {@code null} + * + * @return a non-{@code null} {@link Selectable} + * + * @exception NullPointerException if any argument is {@code null} + */ + public static final Selectable ambiguityReducing(final Selectable s, + final Predicate p, + final ToIntFunction ranker) { Objects.requireNonNull(s, "s"); + Objects.requireNonNull(p, "p"); + Objects.requireNonNull(ranker, "ranker"); + // Relevant bits: // // https://jakarta.ee/specifications/cdi/4.1/jakarta-cdi-spec-4.1#unsatisfied_and_ambig_dependencies @@ -70,24 +108,25 @@ public static final Selectable ambiguityReducing(fin // must") return c -> { final List elements = s.select(c); - if (elements.isEmpty()) { - return List.of(); - } else if (elements.size() == 1) { - return List.of(elements.get(0)); - } + final int size = elements.size(); + switch (size) { + case 0 -> List.of(); + case 1 -> List.of(elements.get(0)); + default -> {} + }; int maxRank = Integer.MIN_VALUE; - final List reductionList = new ArrayList<>(elements.size()); // will never be larger, only smaller + final List reductionList = new ArrayList<>(size); // will never be larger, only smaller boolean reductionListContainsOnlyRankedAlternates = false; for (final E element : elements) { - if (!element.alternate()) { // TODO: eventually this method will go away + if (!p.test(element)) { // TODO: eventually this method will go away // The element is not an alternate. We skip it. continue; } - final int rank = element.rank(); // TODO: eventually this method will go away - if (rank == DEFAULT_RANK) { + final int rank = ranker.applyAsInt(element); + if (rank == 0) { // The element is an alternate. It has the default rank, so no explicit rank. Headed toward ambiguity. No need // to look at maxRank etc. if (reductionListContainsOnlyRankedAlternates) { @@ -98,20 +137,19 @@ public static final Selectable ambiguityReducing(fin } if (reductionList.isEmpty()) { - // The element is an alternate. It has an explicit rank. The reduction list is empty. The element's rank is - // therefore the highest one encountered so far. Add the element to the reduction list. + // The element is an alternate with an explicit rank. The reduction list is empty. The element's rank is + // therefore by definition the highest one encountered so far. Add the element to the reduction list. assert !reductionListContainsOnlyRankedAlternates : "Unexpected reductionListContainsOnlyRankedAlternates: " + reductionListContainsOnlyRankedAlternates; - if (rank > maxRank) { - maxRank = rank; - } + assert rank > maxRank : "rank <= maxRank: " + rank + " <= " + maxRank; // TODO: I think this is correct + maxRank = rank; reductionList.add(element); reductionListContainsOnlyRankedAlternates = true; continue; } if (reductionListContainsOnlyRankedAlternates) { - // The element is an alternate. It has an explicit rank. The reduction list is known to contain only ranked - // alternates (in fact it should contain exactly one). + // The element is an alternate. It has an explicit rank. The (non-empty) reduction list is known to contain + // only ranked alternates (in fact it should contain exactly one). assert reductionList.size() == 1 : "Unexpected reductionList size: " + reductionList; if (rank > maxRank) { // The element's rank is higher than the rank of the (sole) element in the list. Record the new highest rank @@ -141,104 +179,6 @@ public static final Selectable ambiguityReducing(fin }; } - /** - * Returns a {@link Selectable} that caches its results. - * - *

    The cache is unbounded.

    - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @return a non-{@code null} {@link Selectable} - * - * @exception NullPointerException if {@code selectable} is {@code null} - * - * @see #caching(Selectable, BiFunction) - */ - public static Selectable caching(final Selectable selectable) { - final Map> selectionCache = new ConcurrentHashMap<>(); - return Selectables.caching(selectable, selectionCache::computeIfAbsent); - } - - /** - * Returns a {@link Selectable} that caches its results. - * - * @param the criteria type - * - * @param the element type - * - * @param selectable a {@link Selectable}; must not be {@code null} - * - * @param f a {@link BiFunction} that returns a cached result, computing it on demand via its supplied mapping {@link - * Function} if necessary; must not be {@code null}; normally safe for concurrent use by multiple threads; often a - * reference to the {@link ConcurrentHashMap#computeIfAbsent(Object, Function)} method - * - * @return a non-{@code null} {@link Selectable} - * - * @exception NullPointerException if {@code selectable} or {@code f} is {@code null} - * - * @see ConcurrentHashMap#computeIfAbsent(Object, Function) - */ - public static Selectable caching(final Selectable selectable, - final BiFunction>, ? extends List> f) { - Objects.requireNonNull(selectable, "selectable"); - return c -> f.apply(c, selectable::select); - } - - /** - * Returns a {@link Selectable} whose {@link Selectable#select(Object)} method always returns an {@linkplain List#of() - * empty, immutable List}. - * - * @param the criteria type - * - * @param the element type - * - * @return a non-{@code null} {@link Selectable} - */ - public static final Selectable empty() { - return Selectables::empty; - } - - private static final List empty(final C ignored) { - return List.of(); - } - - /** - * Returns a {@link Selectable} using the supplied {@link Collection} as its elements, and the supplied {@link - * BiFunction} as its selector function. - * - *

    There is no guarantee that this method will return new {@link Selectable} instances.

    - * - *

    The {@link Selectable} instances returned by this method may or may not cache their selections.

    - * - *

    The selector function must select a sublist from the supplied {@link Collection} as mediated by the supplied - * criteria. The selector function must additionally be idempotent and must produce a determinate value when given the - * same arguments.

    - * - *

    No validation of these semantics of the selector function is performed.

    - * - * @param the criteria type - * - * @param the element type - * - * @param collection a {@link Collection} of elements from which sublists may be selected; must not be {@code null} - * - * @param f the selector function; must not be {@code null} - * - * @return a {@link Selectable}; never {@code null} - * - * @exception NullPointerException if either {@code collection} or {@code f} is {@code null} - */ - @SuppressWarnings("unchecked") - public static Selectable filtering(final Collection collection, - final BiFunction f) { - Objects.requireNonNull(f, "f"); - return collection.isEmpty() ? empty() : c -> (List)collection.stream().filter(e -> f.apply(e, c)).toList(); - } - /** * {@linkplain Beans#normalize(Collection) Normalizes} the supplied {@link Collection} of {@link Bean}s and returns a * {@link Selectable} for it and the supplied {@link Matcher}. @@ -253,11 +193,11 @@ public static Selectable filtering(final Collection co * * @exception NullPointerException if any argument is {@code null} * - * @see #filtering(Collection, BiFunction) + * @see org.microbean.assign.Selectables#filtering(Collection, BiPredicate) * * @see #ambiguityReducing(Selectable) * - * @see #caching(Selectable) + * @see org.microbean.assign.Selectables#caching(Selectable) * * @see Beans#normalize(Collection) */ @@ -265,7 +205,10 @@ public static final Selectable> typesafeReducing(final C final Matcher m) { Objects.requireNonNull(m, "m"); final List> normalizedBeans = normalize(beans); - return normalizedBeans.isEmpty() ? empty() : filtering(normalizedBeans, (b, c) -> m.test(c, b.id())); + return + normalizedBeans.isEmpty() ? + org.microbean.assign.Selectables.empty() : + org.microbean.assign.Selectables.filtering(normalizedBeans, (b, c) -> m.test(c, b.id())); } } diff --git a/src/main/java/org/microbean/bean/UnsatisfiedReductionException.java b/src/main/java/org/microbean/bean/UnsatisfiedReductionException.java index 23741a0..1a01df9 100644 --- a/src/main/java/org/microbean/bean/UnsatisfiedReductionException.java +++ b/src/main/java/org/microbean/bean/UnsatisfiedReductionException.java @@ -17,10 +17,6 @@ * A {@link ReductionException} indicating that a reduction did not occur because there were no elements to reduce. * * @author Laird Nelson - * - * @see Reducible - * - * @see Reducer */ public final class UnsatisfiedReductionException extends ReductionException { diff --git a/src/test/java/org/microbean/bean/TestBeanSelection.java b/src/test/java/org/microbean/bean/TestBeanSelection.java index 404dd44..6882aeb 100644 --- a/src/test/java/org/microbean/bean/TestBeanSelection.java +++ b/src/test/java/org/microbean/bean/TestBeanSelection.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; +import org.microbean.assign.AttributedType; import org.microbean.assign.Matcher; import org.microbean.construct.Domain; @@ -35,7 +36,7 @@ final class TestBeanSelection { private static final Domain domain = new DefaultDomain(); private static final Matcher matcher = - new IdMatcher(new BeanQualifiersMatcher(), new InterceptorBindingsMatcher(), new BeanTypeMatcher(domain)); + new IdMatcher(new BeanTypeMatcher(domain), new BeanQualifiersMatcher()); private TestBeanSelection() { super(); diff --git a/src/test/java/org/microbean/bean/TestRankedReducer.java b/src/test/java/org/microbean/bean/TestRankedReducer.java deleted file mode 100644 index 07482d7..0000000 --- a/src/test/java/org/microbean/bean/TestRankedReducer.java +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- - * - * Copyright © 2024 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package org.microbean.bean; - -import java.util.List; - -import org.junit.jupiter.api.Test; - -import org.junit.jupiter.params.ParameterizedTest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; - -@Deprecated -final class TestRankedReducer { - - private TestRankedReducer() { - super(); - } - - @Test - final void test0() { - final Ranked a0 = new Ranked() {}; - final Ranked a1 = new Ranked() { - @Override - public final boolean alternate() { return true; } - }; - assertSame(a1, RankedReducer.of().reduce(List.of(a0, a1), null)); - } - - @Test - final void test1() { - final Ranked a0 = new Ranked() { - @Override - public final boolean alternate() { return true; } - }; - final Ranked a1 = new Ranked() {}; - assertSame(a0, RankedReducer.of().reduce(List.of(a0, a1), null)); - } - - @Test - final void test2() { - final Ranked a0 = new Ranked() {}; - final Ranked a1 = new Ranked() {}; - assertNotSame(a0, a1); - assertThrows(AmbiguousReductionException.class, () -> RankedReducer.of().reduce(List.of(a0, a1), null)); - } - - @Test - final void test3() { - final Ranked a0 = new Ranked() { - @Override - public final boolean alternate() { return true; } - }; - final Ranked a1 = new Ranked() { - @Override - public final boolean alternate() { return true; } - }; - assertNotSame(a0, a1); - assertThrows(AmbiguousReductionException.class, () -> RankedReducer.of().reduce(List.of(a0, a1), null)); - } - - @Test - final void test4() { - final Ranked r0 = new Ranked() {}; - final Ranked r1 = new Ranked() { - @Override - public final int rank() { return 1; } - }; - // Surprising, perhaps, but 100% correct: ranks only matter when alternate() returns true. - assertThrows(AmbiguousReductionException.class, () -> RankedReducer.of().reduce(List.of(r0, r1), null)); - } - - @Test - final void test5() { - final Ranked r0 = new Ranked() {}; - final Ranked r1 = new Ranked() {}; - assertNotSame(r0, r1); - // Surprising, perhaps, but 100% correct: ranks only matter when alternate() returns true. - assertThrows(AmbiguousReductionException.class, () -> RankedReducer.of().reduce(List.of(r0, r1), null)); - } - - @Test - final void test6() { - final Ranked r0 = new Ranked() { - @Override - public final int rank() { return 1; } - }; - final Ranked r1 = new Ranked() {}; - // Surprising, perhaps, but 100% correct: ranks only matter when alternate() returns true. - assertThrows(AmbiguousReductionException.class, () -> RankedReducer.of().reduce(List.of(r0, r1), null)); - } - - -} diff --git a/src/test/java/org/microbean/bean/TestReferences.java b/src/test/java/org/microbean/bean/TestReferences.java index e6a5eb9..bab8b07 100644 --- a/src/test/java/org/microbean/bean/TestReferences.java +++ b/src/test/java/org/microbean/bean/TestReferences.java @@ -18,6 +18,8 @@ import org.junit.jupiter.api.Test; +import org.microbean.assign.AttributedType; + final class TestReferences { private TestReferences() { @@ -46,7 +48,7 @@ public DummyReferences references(final AttributedType t) { } @Override - public boolean destroy(final R r) { + public boolean destroy(final Object r) { return false; } diff --git a/src/test/java/org/microbean/bean/TestSelectables.java b/src/test/java/org/microbean/bean/TestSelectables.java new file mode 100644 index 0000000..726fe84 --- /dev/null +++ b/src/test/java/org/microbean/bean/TestSelectables.java @@ -0,0 +1,44 @@ +/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- + * + * Copyright © 2025 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.microbean.bean; + +import java.util.function.Supplier; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import static org.microbean.assign.Qualifiers.anyAndDefaultQualifiers; + +final class TestSelectables { + + private TestSelectables() { + super(); + } + + @Test + final void testMethodReferenceAndNull() { + final String hello = null; + try { + final Supplier s = hello::toString; + fail(); + } catch (final NullPointerException expected) { + + } + } + +}