Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

[![Maven Central](https://img.shields.io/maven-central/v/org.microbean/microbean-assign.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.microbean/microbean-assign)

![0% AI](https://img.shields.io/badge/%F0%9F%A4%96_AI-0%25_%F0%9F%8C%BC-brightgreen)

The microBean™ Assign project provides classes and interfaces assisting with implementing Java type assignment.

# Status
Expand All @@ -27,7 +29,7 @@ dependency:
<groupId>org.microbean</groupId>
<artifactId>microbean-assign</artifactId>
<!-- Always check https://search.maven.org/artifact/org.microbean/microbean-bean for up-to-date available versions. -->
<version>0.0.11</version>
<version>0.0.13</version>
</dependency>
```

Expand Down
28 changes: 8 additions & 20 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>org.microbean</groupId>
<artifactId>microbean-assign</artifactId>
<version>0.0.12-SNAPSHOT</version>
<version>0.0.13-SNAPSHOT</version>

<name>microBean™ Assign</name>
<description>microBean™ Assign: Utility classes for implementing Java type assignment.</description>
Expand Down Expand Up @@ -71,7 +71,7 @@
<!-- maven-javadoc-plugin properties -->
<bottom><![CDATA[Copyright &copy; ${project.inceptionYear}&ndash;{currentYear}, <a href="${project.organization.url}" target="_top">${project.organization.name}</a>. All rights reserved.]]></bottom>
<doctitle>&lt;a href="${project.url}" target="_top"&gt;&lt;span style="font-family:Lobster, cursive;"&gt;µb&lt;/span&gt; ${project.artifactId}&lt;/a&gt; ${project.version}</doctitle>
<links>https://microbean.github.io/microbean-attributes/apidocs/,https://microbean.github.io/microbean-construct/apidocs/</links>
<links>,https://microbean.github.io/microbean-construct/apidocs/</links>
<sourcetab>2</sourcetab>

<!-- maven-release-plugin properties -->
Expand Down Expand Up @@ -118,12 +118,6 @@

<!-- Normal dependencies. -->

<dependency>
<groupId>org.microbean</groupId>
<artifactId>microbean-attributes</artifactId>
<version>0.0.5</version>
</dependency>

<dependency>
<groupId>org.microbean</groupId>
<artifactId>microbean-constant</artifactId>
Expand All @@ -133,20 +127,14 @@
<dependency>
<groupId>org.microbean</groupId>
<artifactId>microbean-construct</artifactId>
<version>0.0.18</version>
<version>0.0.24</version>
</dependency>

</dependencies>
</dependencyManagement>

<dependencies>

<dependency>
<groupId>org.microbean</groupId>
<artifactId>microbean-attributes</artifactId>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.microbean</groupId>
<artifactId>microbean-constant</artifactId>
Expand Down Expand Up @@ -300,7 +288,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>12.3.0</version>
<version>13.2.0</version>
</dependency>
</dependencies>
</plugin>
Expand All @@ -321,7 +309,7 @@
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<version>3.15.0</version>
<configuration>
<compilerArgs>
<arg>-Xlint:all</arg>
Expand All @@ -331,7 +319,7 @@
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.9.0</version>
<version>3.10.0</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
Expand Down Expand Up @@ -433,7 +421,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.20.1</version>
<version>2.21.0</version>
</plugin>
<plugin>
<groupId>io.smallrye</groupId>
Expand All @@ -443,7 +431,7 @@
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.9.0</version>
<version>0.10.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central.sonatype.com</publishingServerId>
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -22,7 +22,6 @@
exports org.microbean.assign;

requires transitive java.compiler;
requires transitive org.microbean.attributes;
requires org.microbean.constant;
requires transitive org.microbean.construct;

Expand Down
34 changes: 17 additions & 17 deletions src/main/java/org/microbean/assign/AbstractTypeMatcher.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,7 +19,6 @@
import java.lang.constant.DynamicConstantDesc;
import java.lang.constant.MethodHandleDesc;

import java.util.Objects;
import java.util.Optional;

import java.util.function.Predicate;
Expand All @@ -35,6 +34,10 @@

import static java.lang.constant.ConstantDescs.BSM_INVOKE;

import static java.lang.constant.MethodHandleDesc.ofConstructor;

import static java.util.Objects.requireNonNull;

/**
* A partial implementation of a {@link Matcher} that tests if one {@link TypeMirror} <dfn>matches</dfn> another.
*
Expand All @@ -49,14 +52,6 @@
public abstract class AbstractTypeMatcher implements Constable, Matcher<TypeMirror, TypeMirror> {


/*
* Static fields.
*/


private static final ClassDesc CD_Domain = ClassDesc.of("org.microbean.construct.Domain");


/*
* Instance fields.
*/
Expand All @@ -77,7 +72,7 @@ public abstract class AbstractTypeMatcher implements Constable, Matcher<TypeMirr
*/
protected AbstractTypeMatcher(final Domain domain) {
super();
this.domain = Objects.requireNonNull(domain, "domain");
this.domain = requireNonNull(domain, "domain");
}


Expand All @@ -86,6 +81,11 @@ protected AbstractTypeMatcher(final Domain domain) {
*/


// I'm leaving these commented-out methods in place for a while to remind me (and future me) of the fact that much of
// CDI's rules around assignability are just poorly written versions of the existing Java Language Specification. For
// example, removing bounds from type variables is not necessary since the supertype of an intersection type is its
// leftmost bound. Similarly, all the logic around wildcards is handled by the contains relation.

// Is t a type that CDI considers to be "parameterized" in its own sense of the word, not the sense used by the Java
// Language Specification?
//
Expand Down Expand Up @@ -286,12 +286,12 @@ protected final boolean covariantlyAssignable(final TypeMirror receiver, final L
*
* @exception NullPointerException if either argument is {@code null}
*
* @see Domain#assignable(TypeMirror, TypeMirror)
* @see Domain#assignable(TypeMirror, TypeMirror)
*/
// Is classOrArrayTypePayload assignable to receiver following the rules of Java assignability
// (i.e. covariance)?
protected boolean covariantlyAssignable(final TypeMirror receiver, final TypeMirror payload) {
return Objects.requireNonNull(receiver, "receiver") == payload || this.domain().assignable(payload, receiver); // yes, "backwards"
return requireNonNull(receiver, "receiver") == payload || this.domain().assignable(payload, receiver); // yes, "backwards"
}

/**
Expand All @@ -312,11 +312,11 @@ protected boolean covariantlyAssignable(final TypeMirror receiver, final TypeMir
* @see Constable#describeConstable()
*/
@Override // Constable
public Optional<? extends ConstantDesc> describeConstable() {
public Optional<DynamicConstantDesc<? extends AbstractTypeMatcher>> describeConstable() {
return (this.domain() instanceof Constable c ? c.describeConstable() : Optional.<ConstantDesc>empty())
.map(domainDesc -> DynamicConstantDesc.of(BSM_INVOKE,
MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName()),
CD_Domain),
ofConstructor(this.getClass().describeConstable().orElseThrow(),
Domain.class.describeConstable().orElseThrow()),
domainDesc));
}

Expand Down Expand Up @@ -371,7 +371,7 @@ protected boolean identical(final TypeMirror receiver, final TypeMirror payload)
// CDI has an undefined notion of "identical to". This method attempts to divine and implement the intent. Recall
// that javax.lang.model.* compares types with "sameType" semantics.
return
Objects.requireNonNull(receiver, "receiver") == Objects.requireNonNull(payload, "payload") ||
requireNonNull(receiver, "receiver") == requireNonNull(payload, "payload") ||
this.domain().sameType(receiver, payload);
}

Expand Down
57 changes: 33 additions & 24 deletions src/main/java/org/microbean/assign/Aggregate.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2025 microBean™.
* Copyright © 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
Expand All @@ -16,14 +16,18 @@
import java.util.Collection;
import java.util.SequencedSet;

import javax.lang.model.element.Element;

import javax.lang.model.AnnotatedConstruct;

import java.util.function.Function;

import static java.util.Collections.unmodifiableSequencedSet;

import static java.util.LinkedHashSet.newLinkedHashSet;

/**
* An object with {@linkplain AttributedElement dependencies}.
* An object with {@linkplain #dependencies() dependencies}.
*
* <p>By default, {@link Aggregate}s have {@linkplain #EMPTY_DEPENDENCIES no dependencies}.</p>
*
Expand All @@ -45,9 +49,9 @@ public interface Aggregate {
public static final SequencedSet<Assignment<?>> EMPTY_ASSIGNMENTS = unmodifiableSequencedSet(newLinkedHashSet(0));

/**
* An immutable, empty {@link SequencedSet} of {@link AttributedElement}s.
* An immutable, empty {@link SequencedSet} of {@link Element}s.
*/
public static final SequencedSet<AttributedElement> EMPTY_DEPENDENCIES = unmodifiableSequencedSet(newLinkedHashSet(0));
public static final SequencedSet<Annotated<Element>> EMPTY_DEPENDENCIES = unmodifiableSequencedSet(newLinkedHashSet(0));


/*
Expand All @@ -56,53 +60,58 @@ public interface Aggregate {


/**
* Returns an immutable, determinate, {@link SequencedSet} of {@link AttributedElement} instances.
* Returns an immutable, determinate, {@link SequencedSet} of {@link Annotated Annotated&lt;? extends Element&gt;}
* instances.
*
* <p>If an {@link AttributedElement} in the set returns a {@link javax.lang.model.element.TypeElement} from its
* {@link AttributedElement#element()} method that represents this {@link Aggregate} implementation, undefined
* behavior, including the possibility of infinite loops, may result (an {@link Aggregate} may not have itself as a
* dependency).</p>
* <p>If an {@link Annotated Annotated&lt;? extends Element&gt;} in the set represents this very {@link Aggregate}
* implementation, undefined behavior, including the possibility of infinite loops, may result (an {@link Aggregate}
* may not have itself as a dependency).</p>
*
* <p>Note that it is permissible for an {@link AttributedElement} in the set to refer to another type by returning a
* {@link javax.lang.model.element.TypeElement} from its {@link AttributedElement#element()} method.</p>
* <p>Note that it is permissible for an {@link Annotated Annotated&lt;? extends Element&gt;} in the set to represent
* another type.</p>
*
* <p>The default implementation of this method returns the value of the {@link #EMPTY_DEPENDENCIES} field.</p>
*
* @return an immutable, determinate, {@link SequencedSet} of {@link AttributedElement} instances; never {@code null}
* @return an immutable, determinate, {@link SequencedSet} of {@link Annotated Annotated&lt;? extends Element&gt;}
* instances; never {@code null}
*
* @see Annotated
*
* @see AttributedElement
* @see Annotated#of(AnnotatedConstruct)
*/
public default SequencedSet<AttributedElement> dependencies() {
public default SequencedSet<? extends Annotated<? extends Element>> 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.
* A convenience method that assigns a contextual reference to each of this {@link Aggregate}'s {@link Annotated
* Annotated&lt;? extends Element&gt;}-typed {@linkplain #dependencies() dependencies} and returns the resulting
* {@link SequencedSet} of {@link Assignment}s.
*
* <p><strong>Note:</strong> Undefined behavior may result if an {@link AttributedElement} in the {@linkplain
* #dependencies() dependencies} represents this {@link Aggregate} implementation (an {@link Aggregate} may not have
* itself as a dependency).</p>
* <p><strong>Note:</strong> Undefined behavior may result if an {@link Annotated Annotated&lt;? extends Element&gt;}
* in the {@linkplain #dependencies() dependencies} represents this {@link Aggregate} implementation (an {@link
* Aggregate} may not have itself as a dependency).</p>
*
* <p>Typically there is no need to override this method.</p>
*
* <p>Usage of this method is not required.</p>
*
* @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}
* @param r a {@link Function} that retrieves a contextual reference suitable for an {@link Annotated Annotated&lt;?
* extends AnnotatedConstruct&gt;}; 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}
*/
// (Convenience.)
public default SequencedSet<? extends Assignment<?>> assign(final Function<? super AttributedType, ?> r) {
final Collection<? extends AttributedElement> ds = this.dependencies();
public default SequencedSet<? extends Assignment<?>> assign(final Function<? super Annotated<? extends AnnotatedConstruct>, ?> r) {
final Collection<? extends Annotated<? extends Element>> ds = this.dependencies();
if (ds == null || ds.isEmpty()) {
return EMPTY_ASSIGNMENTS;
}
final SequencedSet<Assignment<?>> assignments = newLinkedHashSet(ds.size());
ds.forEach(d -> assignments.add(new Assignment<>(d, r.apply(d.attributedType()))));
ds.forEach(d -> assignments.add(new Assignment<>(d, r.apply(d))));
return unmodifiableSequencedSet(assignments);
}

Expand Down
Loading