'Spring boot autowired service all variable fields are null

Currently I have many spring boot services annotated with @Service. Every service works fine and there are no problems. There is a problem only with LogsService. LogsService is implemented the same way as other services such as StaticPageService.

In order to log in a user must use method "onLoginClicked" from LoginViewModel class. LoginViewModel class:

package com.flyingdynamite.jvmbackend.views.login

import com.flyingdynamite.jvmbackend.data.constants.LogCategory
import com.flyingdynamite.jvmbackend.extensions.isNotNull
import com.flyingdynamite.jvmbackend.security.hash.Hash
import com.flyingdynamite.jvmbackend.service.AdminAuthorizationService
import com.flyingdynamite.jvmbackend.service.LogsService
import com.flyingdynamite.jvmbackend.service.UserModelService
import com.flyingdynamite.jvmbackend.util.SystemInformation
import com.flyingdynamite.jvmbackend.util.base.validation.Argon2PasswordHash
import com.flyingdynamite.jvmbackend.util.generator.ApiAccessCredentialsGenerator
import com.flyingdynamite.jvmbackend.util.generator.TextIdGenerator
import com.flyingdynamite.jvmbackend.views.AdminPanelRoute
import com.flyingdynamite.jvmbackend.views.BaseViewModel
import com.flyingdynamite.jvmbackend.views.dashboard.DashboardView
import kotlinx.coroutines.*
import org.apache.commons.lang3.RandomStringUtils
import org.apache.commons.lang3.time.StopWatch
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.annotation.Scope
import org.springframework.stereotype.Component
import org.springframework.util.unit.DataSize
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import java.util.concurrent.TimeUnit

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
open class LoginViewModel : BaseViewModel() {

    private val TAG = "LoginViewModel"

    @Autowired(required = true)
    private lateinit var logsService: LogsService

    @Autowired(required = true)
    private lateinit var userModelService: UserModelService

    @Autowired(required = true)
    private lateinit var adminAuthorizationService: AdminAuthorizationService


    private var loginJob: Job? = null
    private var developerTasksJob: Job? = null

    init {

        viewModelScope.launch {
            setPageTitle("Login")
        }
    }

    override fun onCleared() {
        loginJob?.cancel("onCleared")
        developerTasksJob?.cancel("onCleared")
    }

    //    @PostConstruct
    private fun runScheduledDeveloperTask() {
        logger.warn("runScheduledDeveloperTask")
        if (productionMode) {
            return
        }
        Timer(TAG).schedule(object : TimerTask() {
            override fun run() {
                logger.warn("runDeveloperComputationTask")
                runDeveloperComputationTask()
            }
        }, Date.from(LocalDateTime.now().plusHours(6).atZone(ZoneId.systemDefault()).toInstant()))
    }

    fun onLoginClicked(login: String?, password: String?) {

        if (loginJob != null) {
            return
        }

        loginJob = computationViewModelScope.launch {
            logsService.enqueue(TAG, LogCategory.INFO, "onLoginClicked / login _> ${login} / password _> ${password}")
            println("$TAG -> onLoginClicked / login _> ${login} / password _> ${password}")
            setIsLoading(true)
            setErrorText(null)

            val inputValuesErrorText = inputValuesErrorText(login, password)
            println("$TAG -> onLoginClicked / inputValuesErrorText _> ${inputValuesErrorText} / isEmpty _> ${inputValuesErrorText.isEmpty()}")

            val authorized = adminAuthorizationService.isAuthorized(login!!, password!!)

            val resultError = if (inputValuesErrorText.isNotNull()) {
                inputValuesErrorText
            } else {

                if (authorized) null else localizedTexts.getOrEmpty("wrong_credentials")
            }
            println("$TAG -> onLoginClicked / resultError _> ${resultError}")
            setErrorText(resultError)
            delay(100)
            setIsLoading(false)

            setNavigateTo(
                    if (authorized) Triple(
                            DashboardView::class.java,
                            AdminPanelRoute.DASHBOARD,
                            userModelService.getUserByUsernameOrThrow(login)
                    ) else null
            )
            loginJob = null
//            setNavigateTo(null)
        }
    }

userModelService and adminAuthorizationService have no issues.

LogsService class:

package com.flyingdynamite.jvmbackend.service

import com.flyingdynamite.jvmbackend.data.constants.LogCategory
import com.flyingdynamite.jvmbackend.data.model.LogItem
import com.flyingdynamite.jvmbackend.repository.jpa.LogsJpaRepository
import com.flyingdynamite.jvmbackend.service.exception.NotFoundException
import com.flyingdynamite.jvmbackend.util.AppInfo
import com.flyingdynamite.jvmbackend.util.LogUtils
import com.vaadin.flow.server.WebBrowser
import kotlinx.coroutines.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.annotation.Scope
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.Duration
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import java.util.concurrent.TimeUnit
import javax.persistence.EntityManager
import javax.persistence.EntityManagerFactory
import javax.persistence.PersistenceContext
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.Predicate
import java.util.concurrent.ConcurrentLinkedQueue

@Service
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
open class LogsService : BaseService() {

    private val TAG = "LogService"

    @Autowired(required = true)
    private lateinit var appInfo: AppInfo

    @Autowired(required = true)
    private lateinit var logRepository: LogsJpaRepository

    @Autowired(required = true)
    @PersistenceContext
    private lateinit var entityManager: EntityManager

    @Autowired(required = true)
    private lateinit var entityManagerFactory: EntityManagerFactory


    private val queue: ConcurrentLinkedQueue<LogItem> = ConcurrentLinkedQueue<LogItem>()

    private val cmdLog: Logger by lazy {
        LoggerFactory.getLogger(this::class.java)
    }

//    private val queue: ConcurrentLinkedQueue<LogItem> by lazy {
//        ConcurrentLinkedQueue<LogItem>()
//    }

    private var deleteOlderDays: Int = 30
    private var insertMinLogItemsCount: Int = 100
    private var insertMaxSecondsDifference: Int = 5

    private var isActive: Boolean = true

    private var queueJob: Job? = null

    private val terminatingMessage: String = "TERMINATING !"

    private var displayInCMD: Boolean = true

    @Synchronized
    fun enableDisplayInCMD() {
        displayInCMD = true

        if (isActive) {
            startQueueThreadIfPossible()
        }
    }

    @Synchronized
    fun disableDisplayInCMD() {
        displayInCMD = false

        if (isActive) {
            startQueueThreadIfPossible()
        }
    }

    @Synchronized
    fun activate() {
        if (displayInCMD) {
            cmdLog.trace("activating _ !")
        }
        isActive = true

        startQueueThreadIfPossible()
    }

    @Synchronized
    fun deactivate() {
        if (displayInCMD) {
            cmdLog.warn("DEACTIVATED _ ! ")
        }
        onCleared()
    }

    @Synchronized
    fun onCleared() {
        isActive = false
        queueJob?.cancel("onCleared")

        queueJob = serviceScope.launch {
            delay(TimeUnit.SECONDS.toMillis(2))

            if (displayInCMD) {
                cmdLog.warn("inserting queue all remaining items -> ${queue.size} ")
            }

            insertList(queue.toList())
            queue.clear()
            queueJob = null
        }
    }
}

BaseService class:

package com.flyingdynamite.jvmbackend.service

import com.flyingdynamite.jvmbackend.extensions.FD_CPU_INTENSIVE_LIMITLESS
import com.flyingdynamite.jvmbackend.extensions.FD_IO_LIMITLESS
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers


open class BaseService() {

    protected val serviceScope:CoroutineScope =  CoroutineScope(Dispatchers.FD_IO_LIMITLESS)

    protected val serviceComputationScope: CoroutineScope = CoroutineScope(Dispatchers.FD_CPU_INTENSIVE_LIMITLESS)

    protected fun onException(e: Exception) {
        println("[Exception] -> ${e.message}")
        e.printStackTrace()
    }

}

When user executes onLoginClicked this error occurs:

Exception in thread "pool-2-thread-1" java.lang.NullPointerException
    at com.flyingdynamite.jvmbackend.service.LogsService.enqueue(LogsService.kt:171)
    at com.flyingdynamite.jvmbackend.service.LogsService.enqueue(LogsService.kt:162)
    at com.flyingdynamite.jvmbackend.views.login.LoginViewModel$onLoginClicked$1.invokeSuspend(LoginViewModel.kt:81)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

LogsService.kt:171 -> queue.offer(log) in method enqueue from LogsService class.

If I change the code and execute for example something with serviceScope variable the same error occurs. Then serviceScope is null. Every variable inside LogsService is null when I am trying to use it. Please help mi with this. Where is the mistake ?



Solution 1:[1]

Resolved ! Issue was in the logs but only when logging.level.root=DEBUG was set in application.properties

After long search this was somewhere in the logs:

cannot get proxied via CGLIB: Calls to this method will NOT be routed to the >target instance and might lead to NPEs against uninitialized fields in the >proxy instance.

After adding "open" to every method of LogsService class - log entry is not displaying anymore. Seems it is fixed. Not getting any NPE anymore.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Reckos