Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring #14

Merged
merged 1 commit into from
Oct 9, 2024
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
17 changes: 13 additions & 4 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Notes

## Factories, Producers, etc.
## Model

For every `Factory`:
* Grab its dependencies
* Ask a `Selectable` to

## Obsolete, or Unmaintained

### Factories, Producers, etc.

A `Factory` is the user-visible creation mechanism.

Expand Down Expand Up @@ -44,7 +52,9 @@ Instead of taking a `Chain` it should take the raw materials to make a chain tha
* A supplier of arguments (`Supplier<? extends Object[]>`)

This also performs constructor interception.
** We can break this down further into an "instantiator", which comes up with construction arguments via dependency resolution, and an interceptor that intercepts these arguments and

** We can break this down further into an "instantiator", which comes up with construction arguments via dependency
resolution, and an interceptor that intercepts these arguments and


** This _may_ (haven't decided yet) decompose into something that does the resolution, and the "instantiator", whose job
Expand All @@ -53,8 +63,7 @@ This also performs constructor interception.
* A `PostInitializer`. This calls the product's `postConstruct()` callbacks.
* A `PreDestructor`. This calls the product's `preDestroy()` callbacks.


## `AutoCloseableRegistry` Instances
### `AutoCloseableRegistry` Instances

An `AutoCloseableRegistry` is an `AutoCloseable` and a collection of `AutoCloseable`s. Therefore it is also a tree.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ dependency:
<groupId>org.microbean</groupId>
<artifactId>microbean-bean</artifactId>
<!-- Always check https://search.maven.org/artifact/org.microbean/microbean-bean for up-to-date available versions. -->
<version>0.0.9</version>
<version>0.0.10</version>
</dependency>
```

Expand Down
7 changes: 4 additions & 3 deletions src/main/java/org/microbean/bean/AbstractFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

import java.util.Objects;

// TODO: this is mildly fouled up. The spirit is right but the implementation is not so hot.
// TODO: this is mildly fouled up. The spirit is right but the implementation is not so hot. Retaining for now so I can
// see how the subsidiary parts fit together, which is worth knowing.
@Deprecated(forRemoval = true)
abstract class AbstractFactory<I> implements Factory<I> {

Expand Down Expand Up @@ -55,8 +56,8 @@ protected AbstractFactory(final Producer<I> producer, // production and destruct

@Override // Factory<I>
public I create(final Request<I> r) {
// Produce the product, initialize the product, post-initialize the product, apply business method interceptions to
// the product, return the product
// Produce the product (with interceptions or not; producer is in charge of that), initialize the product,
// post-initialize the product, apply business method interceptions to the product, return the (possibly intercepted) product
return this.interceptionsApplicator.apply(this.postInitializer.postInitialize(this.initializer.initialize(this.producer.produce(r), r), r), r);
}

Expand Down
48 changes: 35 additions & 13 deletions src/main/java/org/microbean/bean/Aggregate.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import java.util.SequencedSet;

/**
* An object with {@linkplain Dependency dependencies}.
* An object with {@linkplain AttributedElement dependencies}.
*
* <p>By default, {@link Aggregate}s have no dependencies.</p>
*
Expand All @@ -30,24 +30,41 @@
*/
public interface Aggregate {


/*
* Static fields.
*/


/**
* An immutable, empty {@link SequencedSet}.
* An immutable, empty {@link SequencedSet} of {@link Assignment}s.
*/
public static final SequencedSet<Dependency> EMPTY_DEPENDENCIES = Collections.unmodifiableSequencedSet(new LinkedHashSet<>(0));
public static final SequencedSet<Assignment<?>> EMPTY_ASSIGNMENTS = Collections.unmodifiableSequencedSet(new LinkedHashSet<>(0));

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


/*
* Default instance methods.
*/


/**
* Returns an unmodifiable {@link SequencedSet} of {@link Dependency} instances.
* Returns an unmodifiable {@link SequencedSet} of {@link AttributedElement} instances.
*
* @return an unmodifiable {@link SequencedSet} of {@link Dependency} instances; never {@code null}
* @return an unmodifiable {@link SequencedSet} of {@link AttributedElement} instances; never {@code null}
*
* @see Dependency
* @see AttributedElement
*/
public default SequencedSet<Dependency> dependencies() {
public default SequencedSet<AttributedElement> dependencies() {
return EMPTY_DEPENDENCIES;
}

/**
* Assigns a contextual reference to each of this {@link Aggregate}'s {@link Dependency} instances and returns the
* Assigns a contextual reference to each of this {@link Aggregate}'s {@link AttributedElement} instances and returns the
* resulting {@link List} of {@link Assignment}s.
*
* @param r a {@link Request}; must not be {@code null}
Expand All @@ -56,11 +73,16 @@ public default SequencedSet<Dependency> dependencies() {
*
* @exception NullPointerException if {@code r} is {@code null}
*/
public default List<Assignment> assign(final Request<?> r) {
final Collection<? extends Dependency> ds = this.dependencies();
return ds == null || ds.isEmpty() ? List.of() : ds.stream()
.map(d -> new Assignment(d, r.reference(d.beanSelectionCriteria(), r)))
.toList();
public default SequencedSet<? extends Assignment<?>> assign(final Request<?> r) {
final Collection<? extends AttributedElement> ds = this.dependencies();
if (ds == null || ds.isEmpty()) {
return EMPTY_ASSIGNMENTS;
}
final SequencedSet<Assignment<?>> assignments = new LinkedHashSet<>();
for (final AttributedElement d : ds) {
assignments.add(new Assignment<>(d, r.reference(d.attributedType())));
}
return Collections.unmodifiableSequencedSet(assignments);
}

}
26 changes: 8 additions & 18 deletions src/main/java/org/microbean/bean/Assignment.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
import java.util.Objects;

/**
* An assignment of a contextual reference to a {@link Dependency}, usually as found by a {@link Request}.
* An assignment of a contextual reference to an {@link AttributedElement}, usually as {@linkplain
* Request#reference(BeanSelectionCriteria) completed by} a {@link Request}.
*
* @param dependency the {@link Dependency}; must not be {@code null}
* @param <R> the type of contextual reference
*
* @param assignee the {@link AttributedElement}; must not be {@code null}
*
* @param value the contextual reference; may be {@code null}
*
Expand All @@ -27,30 +30,17 @@
// 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 record Assignment(Dependency dependency, Object value) {
public record Assignment<R>(AttributedElement assignee, R value) {

/**
* Creates a new {@link Assignment}.
*
* @param dependency the {@link Dependency}; must not be {@code null}
* @param assignee the {@link AttributedElement}; must not be {@code null}
*
* @param value the contextual reference; may be {@code null}
*/
public Assignment {
Objects.requireNonNull(dependency, "dependency");
}

/**
* Creates a new {@link Assignment}.
*
* @param d the {@link Dependency}; must not be {@code null}
*
* @param r a {@link Request} used to locate the contextual reference; must not be {@code null}
*
* @exception NullPointerException if {@code r} is {@code null}
*/
public Assignment(final Dependency d, final Request<?> r) {
this(d, r.reference(d.beanSelectionCriteria(), r));
Objects.requireNonNull(assignee, "assignee");
}

}
84 changes: 84 additions & 0 deletions src/main/java/org/microbean/bean/AttributedElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* -*- 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.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.constant.Constables;

import org.microbean.qualifier.NamedAttributeMap;

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

import static org.microbean.lang.ConstantDescs.CD_Element;

/**
* An {@link Element} that has been decorated with {@linkplain NamedAttributeMap attributes}.
*
* <p>Dependency injection frameworks often refer to this sort of thing as an <dfn>injection point</dfn>.</p>
*
* @param element a non-{@code null} {@link Element}
*
* @param attributes a non-{@code null} {@link List} of {@link NamedAttributeMap} instances representing attributes
*
* @author <a href="https://about.me/lairdnelson/" target="_top">Laird Nelson</a>
*/
public final record AttributedElement(Element element, List<NamedAttributeMap<?>> attributes) implements Constable {

public AttributedElement {
Objects.requireNonNull(element, "element");
attributes = List.copyOf(attributes);
}

public final TypeMirror type() {
return this.element().asType();
}

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 <code>Optional</code>} if it could not be described.
*
* @return an {@link Optional} containing a {@link ConstantDesc} describing this {@link AttributedType}, or an
* {@linkplain Optional#isEmpty() empty <code>Optional</code>} if it could not be describe; never {@code null}
*/
@Override // Constable
public Optional<? extends ConstantDesc> describeConstable() {
return this.element() instanceof Constable e ? e.describeConstable() : Optional.<ConstantDesc>empty()
.flatMap(elementDesc -> Constables.describeConstable(this.attributes())
.map(attributesDesc -> DynamicConstantDesc.of(BSM_INVOKE,
MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName()),
CD_Element,
CD_List),
elementDesc,
attributesDesc)));
}

}
70 changes: 70 additions & 0 deletions src/main/java/org/microbean/bean/AttributedType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* -*- 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.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.constant.Constables;

import org.microbean.qualifier.NamedAttributeMap;

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

import static org.microbean.lang.ConstantDescs.CD_TypeMirror;

public final record AttributedType(TypeMirror type, List<NamedAttributeMap<?>> attributes) implements Constable {

public AttributedType {
type = switch (type.getKind()) {
case ARRAY, BOOLEAN, BYTE, CHAR, DECLARED, DOUBLE, FLOAT, INT, LONG, SHORT -> type;
case ERROR, EXECUTABLE, INTERSECTION, MODULE, NONE, NULL, OTHER, PACKAGE, TYPEVAR, UNION, VOID, WILDCARD ->
throw new IllegalArgumentException("type: " + type);
};
attributes = List.copyOf(attributes);
}

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 <code>Optional</code>} if it could not be described.
*
* @return an {@link Optional} containing a {@link ConstantDesc} describing this {@link AttributedType}, or an
* {@linkplain Optional#isEmpty() empty <code>Optional</code>} if it could not be describe; never {@code null}
*/
@Override // Constable
public Optional<? extends ConstantDesc> describeConstable() {
return this.type() instanceof Constable t ? t.describeConstable() : Optional.<ConstantDesc>empty()
.flatMap(typeDesc -> Constables.describeConstable(this.attributes())
.map(attributesDesc -> DynamicConstantDesc.of(BSM_INVOKE,
MethodHandleDesc.ofConstructor(ClassDesc.of(this.getClass().getName()),
CD_TypeMirror,
CD_List),
typeDesc,
attributesDesc)));
}

}
4 changes: 2 additions & 2 deletions src/main/java/org/microbean/bean/Bean.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
/**
* A ({@link Constable}) pairing of an {@link Id} with a {@link Factory}.
*
* @param <I> the type of the contextual instances the associaed {@link Factory} creates
* @param <I> the type of the contextual instances the associated {@link Factory} creates
*
* @param id the {@link Id}; must not be {@code null}
*
Expand Down Expand Up @@ -77,7 +77,7 @@ public final <X> Bean<X> cast() {
}

@Override // Aggregate
public final SequencedSet<Dependency> dependencies() {
public final SequencedSet<AttributedElement> dependencies() {
return this.factory().dependencies();
}

Expand Down
Loading
Loading