3232import java .util .ArrayList ;
3333import java .util .Collection ;
3434import java .util .IdentityHashMap ;
35+ import java .util .LinkedHashSet ;
3536import java .util .List ;
3637import java .util .Objects ;
3738import java .util .Optional ;
3839import java .util .Set ;
3940import java .util .concurrent .ConcurrentHashMap ;
4041import java .util .concurrent .CopyOnWriteArrayList ;
4142import java .util .function .BiFunction ;
43+ import java .util .function .Predicate ;
4244import java .util .function .Supplier ;
4345import java .util .stream .Collectors ;
4446import java .util .stream .Stream ;
@@ -154,6 +156,36 @@ public Binding<T> to(final Supplier<T> supplier) {
154156
155157 return addBinding (dependency , new SupplierBinding <>(dependency , supplier ));
156158 }
159+
160+ @ Override
161+ public Binding <T > toOverriding (final T value ) {
162+ final var dependency = IndependentDependency .of (
163+ typeUsage ,
164+ this .injectionFramework ::getQualifierAnnotationTypes );
165+ return replaceBinding (dependency , SingletonValueBinding .of (dependency , value ));
166+ }
167+
168+ @ Override
169+ public Binding <T > toOverriding (final Class <? extends T > concreteClass ) {
170+ Objects .requireNonNull (concreteClass , "The Binding Value Class must not be null" );
171+ final var dependency = IndependentDependency .of (
172+ typeUsage ,
173+ this .injectionFramework ::getQualifierAnnotationTypes );
174+ final var typeDescriptor = codeModel .getJDKTypeDescriptor (concreteClass )
175+ .orElseThrow (() -> new IllegalArgumentException (
176+ "Could not resolve a TypeDescriptor for " + concreteClass ));
177+ return replaceBinding (dependency , this .injectionFramework .isSingleton (typeDescriptor )
178+ ? new LazySingletonClassBinding <>(dependency , concreteClass )
179+ : new NonSingletonClassBinding <T >(dependency , concreteClass ));
180+ }
181+
182+ @ Override
183+ public Binding <T > toOverriding (final Supplier <T > supplier ) {
184+ final var dependency = IndependentDependency .of (
185+ typeUsage ,
186+ this .injectionFramework ::getQualifierAnnotationTypes );
187+ return replaceBinding (dependency , new SupplierBinding <>(dependency , supplier ));
188+ }
157189 };
158190 }
159191
@@ -175,6 +207,96 @@ private <T> Binding<T> addBinding(final Dependency dependency, final Binding<T>
175207 return binding ;
176208 }
177209
210+ /**
211+ * Replaces or adds the specified {@link Dependency} {@link Binding} without throwing when a binding
212+ * already exists.
213+ *
214+ * @param dependency the {@link Dependency}
215+ * @param binding the {@link Binding}
216+ * @return the {@link Binding} that was registered
217+ */
218+ private <T > Binding <T > replaceBinding (final Dependency dependency , final Binding <T > binding ) {
219+ this .bindingsByDependency .put (dependency , binding );
220+ return binding ;
221+ }
222+
223+ @ Override
224+ @ SuppressWarnings ("unchecked" )
225+ public <T > BindingBuilder <T > bind (final T value ) {
226+ Objects .requireNonNull (value , "The value must not be null" );
227+
228+ final var codeModel = this .injectionFramework .codeModel ();
229+ final var type = (Class <T >) value .getClass ();
230+ final var typeUsage = codeModel .getTypeUsage (type );
231+
232+ return new AbstractBindingBuilder <>(this .injectionFramework , typeUsage ) {
233+ @ Override
234+ public Binding <T > to (final T v ) {
235+ final var dependency = IndependentDependency .of (
236+ typeUsage ,
237+ this .injectionFramework ::getQualifierAnnotationTypes );
238+ return addBinding (dependency , SingletonValueBinding .of (dependency , v ));
239+ }
240+
241+ @ Override
242+ public Binding <T > to (final Class <? extends T > concreteClass ) {
243+ Objects .requireNonNull (concreteClass , "The Binding Value Class must not be null" );
244+ final var dependency = IndependentDependency .of (
245+ typeUsage ,
246+ this .injectionFramework ::getQualifierAnnotationTypes );
247+ final var typeDescriptor = codeModel .getJDKTypeDescriptor (concreteClass )
248+ .orElseThrow (() -> new IllegalArgumentException (
249+ "Could not resolve a TypeDescriptor for " + concreteClass ));
250+ return addBinding (dependency , this .injectionFramework .isSingleton (typeDescriptor )
251+ ? new LazySingletonClassBinding <>(dependency , concreteClass )
252+ : new NonSingletonClassBinding <>(dependency , concreteClass ));
253+ }
254+
255+ @ Override
256+ public Binding <T > to (final Supplier <T > supplier ) {
257+ final var dependency = IndependentDependency .of (
258+ typeUsage ,
259+ this .injectionFramework ::getQualifierAnnotationTypes );
260+ return addBinding (dependency , new SupplierBinding <>(dependency , supplier ));
261+ }
262+
263+ @ Override
264+ public void asAllInterfaces () {
265+ asAllInterfaces (iface -> !iface .getPackageName ().startsWith ("java." ));
266+ }
267+
268+ @ Override
269+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
270+ public void asAllInterfaces (final Predicate <Class <?>> filter ) {
271+ Objects .requireNonNull (filter , "The filter must not be null" );
272+ collectInterfaces (type , new LinkedHashSet <>())
273+ .stream ()
274+ .filter (filter )
275+ .forEach (iface -> InjectionContext .this .bind ((Class ) iface ).to (value ));
276+ }
277+ };
278+ }
279+
280+ /**
281+ * Collects all interfaces from the type hierarchy of the given class, including inherited ones,
282+ * into the provided accumulator set.
283+ *
284+ * @param type the class to walk
285+ * @param result the set to accumulate interfaces into
286+ * @return the same set, populated
287+ */
288+ private static Set <Class <?>> collectInterfaces (final Class <?> type , final Set <Class <?>> result ) {
289+ if (type == null || type == Object .class ) {
290+ return result ;
291+ }
292+ for (final Class <?> iface : type .getInterfaces ()) {
293+ result .add (iface );
294+ collectInterfaces (iface , result );
295+ }
296+ collectInterfaces (type .getSuperclass (), result );
297+ return result ;
298+ }
299+
178300 @ Override
179301 @ SuppressWarnings ("unchecked" )
180302 public <T > MultiBinder <T > bindSet (final Class <T > type ) {
0 commit comments