[#injecting-services]
= Injecting services

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you 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.
:page-partial:


Apache Isis runs on top of Spring Boot, and uses Spring Boot for dependency injection, both the application's own domain services and also the many additional services defined by the framework (such as xref:refguide:applib:index/services/repository/RepositoryService.adoc[RepositoryService]).

Since this is a core capability of Spring, it's worth checking out Spring's link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-collaborators[documentation] on the topic.

[TIP]
====
Injection is requested using the JEE link:https://docs.oracle.com/javaee/7/api/javax/inject/Inject.html[@javax.inject.Inject] annotation.
This is described in Spring's documentation, link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-standard-annotations[using JSR330 standard annotations].

It is also possible to use Spring's own link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html[@Autowired] annotation.
Since the two annotations are effectively equivalent, we recommend using the JEE standard.
====

However, not only does Apache Isis use Spring to autowire domain services into other services, the framework _also_ ensures that services are injected into any domain object (eg xref:overview.adoc#domain-entities[entity], xref:overview.adoc#view-models[view model], xref:overview.adoc#mixins[mixins], xref:testing:fixtures:about.adoc#fixture-scripts[fixture script], xref:refguide:applib:index/spec/Specification.adoc[specification] etc).
This is key enabler to place functionality in the "right place", eg in a domain entity/view model itself, or in a mixin.


There are three ways in which to inject the domain services:

* constructor injection (further discussion in the Spring documentation, link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-constructor-injection[here])
+
This is recommended approach, but note that it is only supported for domain services, NOT for other domain object types.

* setter injection (further discussion link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-setter-injection[here])

* field injection

Whether you use setter or field injection for domain objects etc is a matter of style.
Generally field injection is somewhat frowned up.



== Constructor Injection.

As noted above, constructor injection is only available for domain services.
For example:
[source,java]
.CustomerRepository.java
----
import org.springframework.data.repository.Repository;      // <.>

@Repository
public class CustomerRepository {
    private final RepositoryService repositoryService;
    public CustomerRepository(
                final RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }
    // ...
}
----
<.> indicates this is a repository service.

If you wish, Project Lombok can be used to remove some of the boilerplate:

[source,java]
.CustomerRepository.java
----
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor(onConstructor_ = {@Inject} )   // <.>
public class CustomerRepository {
    private final RepositoryService repositoryService;
    // ...
}
----
<.> Generates a constructor for all `final` fields.

If the layering between services is well defined, as in the above example (application `CustomerRepository` depends upon framework `RepositoryService`), then constructor injection should work out.

However, Spring does not support


TODO: Cyclic dependencies

link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-dependency-resolution[Dependency Resolution Process], ("Circular dependencies" sidebar).

TODO: Provider<>

== Setter and Field Injection

Setter or field injection must be used all objects _other_ than domain services.
For example, setter injection is:

[source,java]
----
import javax.inject.Inject;

public class Customer {
    ...
    OrderRepository orderRepository;
    @Inject                                                 // <.>
    public void setOrderRepository(orderRepository) {
        this.orderRepository = orderRepository;
    }
}
----
<.> The framework injects the domain service into the entity, before any further interactions with it.

It's not necessary for the visibility to be `public`, so it should be as restrictive as possible.
In many cases, default visibility will work (assuming unit tests that mock the dependency are in the same package).

Some of the boilerplate can be removed using Project Lombok:

[source,java]
----
import javax.inject.Inject;
import lombok.Setter;

public class Customer {
    ...
    @Setter(value= AccessLevel.PACKAGE, onMethod_ = {Inject.class}) // <.>
    OrderRepository orderRepository;
}
----
<.> Generates a package-level setter, annotated with `@Inject`

If you want to use field injection, then this is simply:

[source,java]
----
import javax.inject.Inject;

public class Customer {
    ...
    @Inject OrderRepository orderRepository;
}
----

\... and live with or disable any IDE warnings relating to field injection.

Using default visibility here still allows the field to be mocked out within unit tests (if placed in the same package as the code under test).


== Multiple Implementations

If there is more than one implementation of the service, then a specific implementation can be requested using either Spring's link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html[@Primary] annotation (further discussion link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation-primary[here]) or Spring's link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html[Qualifier] annotation (further discussion link:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation-qualifiers[here]).

All of the domain services provided by Apache Isis' are annotated with `@Qualifier` to enable this.


== Injecting Lists of Services

It's also possible to inject a list of services:

[source,java]
----
import javax.inject.Inject;

public class DocumentService {
    ...
    @Inject
    List<PaperclipFactory> paperclipFactories;
}
----

These will be in the order as defined by the `@javax.annotation.Priority` annotation.

This pattern can be useful when implementing the link:https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern[chain of responsibility] design pattern, that is, looking for the first implementation that can handle a request.

It is also useful to "broadcast" or fan out an implementation.
For example, the framework defines the xref:refguide:applib:index/services/publishing/spi/ExecutionSubscriber.adoc[ExecutionSubscriber] SPI, which is used to publish xref:refguide:schema:ixn.adoc[Interaction Execution]s to external systems.
The framework provides a simple logging implementation, which will always be called.
All other implementations available will also be called.


== Injecting `IsisSessionScope`d services

Most domain services are application-scoped, in other words they are stateless global singletons that are shared by all concurrent requests.

A small number of framework-provided services are annotated using xref:refguide:applib:index/annotation/InteractionScope.adoc[@IsisSessionScope].
This means that they are stateful and scoped with each isis session, in other words HTTP request.
One such service is xref:refguide:applib:index/services/queryresultscache/QueryResultsCache.adoc[QueryResultsCache], used for performance caching.

These domain services must be requested using a slightly different idiom, using the `Provider` interface.
For example:

[source,java]
----
import javax.inject.Inject;
import javax.inject.Provider;

public class Customer {
    ...
    @Inject OrderRepository orderRepository;
    @Inject Provider<QueryResultsCache> queryResultsCacheProvider;  // <.>

    public List<Order> getOrders() {
        Customer customer = this;
        return queryResultsCacheProvider
                .get()                                              // <.>
                .execute(
                    () -> orderRepository.findByCustomer(customer),
                    Customer.class, "getOrders",
                    customer)
        );
}
----
<.> inject a `Provider` for the service, not directly
<.> Get the cache from the provider

If you accidentally inject the service directly (without being wrapped in `Provider`), then the framework will detect this and fail-fast.
