Inspectopedia Help

Application service assigned to a static final field or immutable property

Reports assignments of application services to static final fields / immutable properties.

Note: Hereinafter, static in Kotlin refers to members of non-anonymous objects or top-level declarations.

Such services' assignments contribute to global state and make it impossible to tear down an application and set up another one in tests, therefore, repeated tests in the same process may fail. The only exception is an explicit constructor call to store dummy/default instances.

The recommended way to avoid storing services is to retrieve a service locally. Alternatively, one can wrap it in java.util.function.Supplier (Java, Kotlin) or convert the property to a function (Kotlin).

Example (Java):

// Bad: private static final ManagingFS ourInstance = ApplicationManager.getApplication().getService(ManagingFS.class);
// Good: private static final Supplier<ManagingFS> ourInstance = CachedSingletonsRegistry.lazy(() -> { return ApplicationManager.getApplication().getService(ManagingFS.class); });
// Exception: private static final UniqueVFilePathBuilder DUMMY_BUILDER = new UniqueVFilePathBuilder()

While services' assignments to properties without backing fields don't cause the aforementioned problem, using an explicit getInstance() method to retrieve a service is preferred over using a property:

  • It makes it clearer on the call site that it can involve loading the service, which might not be cheap.

  • Loading the service can throw an exception, and having an exception thrown by a method call is less surprising than if it was caused by property access.

  • (Over-)using properties may be error-prone in a way that it might be accidentally changed to a property with an initializer instead of the correct (but more verbose) property with a getter, and that change can easily be overlooked.

  • Using the method instead of a property keeps MyApplicationService.getInstance() calls consistent when used both in Kotlin, and Java.

  • Using the method keeps MyApplicationService.getInstance() consistent with MyProjectService.getInstance(project), both on the declaration and call sites.

For better tooling performance, it is always advised to keep an explicit method return type.

Example:

@Service class MyApplicationService { companion object { @JvmStatic val instance: MyApplicationService // bad get() = service() } }
@Service class MyApplicationService { companion object { @JvmStatic fun getInstance(): MyApplicationService = service() // good } }

New in 2023.3

Locating this inspection

By ID

Can be used to locate inspection in e.g. Qodana configuration files, where you can quickly enable or disable it, or adjust its settings.

ApplicationServiceAsStaticFinalFieldOrProperty
Via Settings dialog

Path to the inspection settings via IntelliJ Platform IDE Settings dialog, when you need to adjust inspection settings directly from your IDE.

Settings or Preferences | Editor | Inspections | Plugin DevKit | Code

Availability

By default bundled with

IntelliJ IDEA 2024.1, Qodana for JVM 2024.1,

Can be installed with plugin

Plugin DevKit, 241.18072

Last modified: 18 June 2024