001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2023–2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.bean; 015 016import java.lang.constant.ClassDesc; 017import java.lang.constant.Constable; 018import java.lang.constant.ConstantDesc; 019import java.lang.constant.DynamicConstantDesc; 020import java.lang.constant.MethodHandleDesc; 021 022import java.util.Objects; 023import java.util.Optional; 024import java.util.SequencedSet; 025 026import java.util.function.Function; 027 028import static java.lang.constant.ConstantDescs.BSM_INVOKE; 029 030/** 031 * A ({@link Constable}) pairing of an {@link Id} with a {@link Factory}. 032 * 033 * @param <I> the type of the contextual instances the associated {@link Factory} creates 034 * 035 * @param id the {@link Id}; must not be {@code null} 036 * 037 * @param factory the {@link Factory}; must not be {@code null} 038 * 039 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 040 * 041 * @see Factory 042 * 043 * @see Id 044 */ 045public final record Bean<I>(Id id, Factory<I> factory) implements Aggregate, Constable, Ranked { 046 047 /** 048 * Creates a new {@link Bean}. 049 * 050 * @param id the {@link Id}; must not be {@code null} 051 * 052 * @param factory the {@link Factory}; must not be {@code null} 053 * 054 * @exception NullPointerException if either argument is {@code null} 055 */ 056 public Bean { 057 Objects.requireNonNull(id, "id"); 058 Objects.requireNonNull(factory, "factory"); 059 } 060 061 @Override // Ranked 062 public final boolean alternate() { 063 return this.id().alternate(); 064 } 065 066 @Override // Aggregate 067 public final SequencedSet<? extends Assignment<?>> assign(final Function<? super AttributedType, ?> r) { 068 return this.factory().assign(r); 069 } 070 071 /** 072 * Returns this {@link Bean}, forcibly cast appropriately. 073 * 074 * @param <X> the type of contextual instances this {@link Bean} creates 075 * 076 * @return this {@link Bean} 077 * 078 * @exception ClassCastException if the cast is inappropriate 079 */ 080 @SuppressWarnings("unchecked") 081 public final <X> Bean<X> cast() { 082 return (Bean<X>)this; 083 } 084 085 @Override // Aggregate 086 public final SequencedSet<AttributedElement> dependencies() { 087 return this.factory().dependencies(); 088 } 089 090 @Override // Constable 091 public final Optional<DynamicConstantDesc<Bean<I>>> describeConstable() { 092 return (this.factory() instanceof Constable c ? c.describeConstable() : Optional.<ConstantDesc>empty()) 093 .flatMap(factoryDesc -> this.id().describeConstable() 094 .map(idDesc -> DynamicConstantDesc.of(BSM_INVOKE, 095 MethodHandleDesc.ofConstructor(ClassDesc.of(Bean.class.getName()), 096 ClassDesc.of(Id.class.getName()), 097 ClassDesc.of(Factory.class.getName())), 098 idDesc, 099 factoryDesc))); 100 } 101 102 @Override // Record (Object) 103 public final boolean equals(final Object other) { 104 return this == other || other != null && this.getClass() == other.getClass() && this.id().equals(((Bean<?>)other).id()); 105 } 106 107 @Override // Record (Object) 108 public final int hashCode() { 109 return this.id().hashCode(); 110 } 111 112 @Override // Ranked 113 public final int rank() { 114 return this.id().rank(); 115 } 116 117}