All Downloads are FREE. Search and download functionalities are using the official Maven repository.

yakworks.testing.grails.GrailsAppBuilder.groovy Maven / Gradle / Ivy

There is a newer version: 7.3.79
Show newest version
/*
* Copyright 2022 Yak.Works - Licensed under the Apache License, Version 2.0 (the "License")
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
package yakworks.testing.grails

import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic

import org.grails.config.PropertySourcesConfig
import org.grails.spring.context.support.GrailsPlaceholderConfigurer
import org.grails.spring.context.support.MapBasedSmartPropertyOverrideConfigurer
import org.grails.testing.GrailsApplicationBuilder
import org.grails.transaction.TransactionManagerPostProcessor
import org.springframework.beans.MutablePropertyValues
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.beans.factory.config.ConstructorArgumentValues
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.beans.factory.support.RootBeanDefinition
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.AnnotationConfigUtils
import org.springframework.context.support.ConversionServiceFactoryBean
import org.springframework.context.support.StaticMessageSource
import org.springframework.core.annotation.AnnotationAttributes
import org.springframework.core.env.ConfigurableEnvironment

import gorm.tools.ConfigDefaults
import grails.core.GrailsApplication
import grails.core.support.proxy.DefaultProxyHandler
import grails.util.Holders

/**
 * Copied in from grails-testing-support Created by jameskleeh on 5/31/17.
 * Adds the following,
 * - override to use AnnotationConfigApplicationContext
 * -
 */
@CompileStatic
class GrailsAppBuilder extends GrailsApplicationBuilder {

    //HACK, whether to create context.'annotation-config'() being needed in the registerBeans
    //The order is strange and if we dont do annotation-config when using DataRepoTest then we get the following injection failure
    //bean with name 'constraintRegistry': Unsatisfied dependency expressed through method 'setConstraintFactories' parameter 0;
    // ...NoSuchBeanDefinitionException:
    // ...No qualifying bean of type 'org.grails.datastore.gorm.validation.constraints.factory.ConstraintFactory[]'
    boolean isDataRepoTest = true

    @CompileStatic
    static class NotRequiredAutowiredAnnotationBeanPostProcessor extends AutowiredAnnotationBeanPostProcessor{

        NotRequiredAutowiredAnnotationBeanPostProcessor() {
            super()
        }

        @Override
        protected boolean determineRequiredStatus(AnnotationAttributes ann) {
            return false
        }
    }

    @Override
    protected ConfigurableApplicationContext createMainContext(Object servletContext) {
        ConfigurableApplicationContext context = new AnnotationConfigApplicationContext()

        ClassLoader applicationClassLoader = this.class.classLoader
        ConfigurableEnvironment configuredEnvironment = context.getEnvironment()

        ConfigurableBeanFactory beanFactory = context.getBeanFactory()
        //setup injection beans that are required=false
        //createAutoWiredBean(beanFactory)
        //runs registerGrailsAppPostProcessorBean(beanFactory) and AnnotationConfigUtils.registerAnnotationConfigProcessors
        prepareContext(context, beanFactory)

        context.register(TestConfiguration)
        context.scan("yakworks.gorm.config")


        //replace with the one that is required=false
        //context.removeBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
        //assert !context.getBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
        context.registerBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
            BeanDefinitionBuilder
                .rootBeanDefinition(NotRequiredAutowiredAnnotationBeanPostProcessor)
                .addPropertyValue("requiredParameterValue", "false")
                .getBeanDefinition())

        //refresh striggers the context build, all the spring bean closures with run at this point.
        context.refresh()
        context.registerShutdownHook()
        context
    }

    @Override
    //so we can remove the context.'annotation-config'
    @CompileDynamic
    @SuppressWarnings(['UnnecessarySelfAssignment'])
    void registerBeans(GrailsApplication grailsApplication) {

        defineBeans(grailsApplication) { ->
            conversionService(ConversionServiceFactoryBean)

            // "${AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME}"(AutowiredAnnotationBeanPostProcessor) {
            //     requiredParameterValue = false
            // }

            xmlns context: "http://www.springframework.org/schema/context"
            // adds AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor and others
            // see org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors method
            //NOTE: commented out as it conflicts with the overrides to replace bean that has required=false as default
            //XXX when removing the the blow up happens in DataTestSetupSpecInterceptor.configureDataTest
            // this line:
            //   applicationContext.getBean('constraintRegistry', ConstraintRegistry).addConstraint(UniqueConstraint)
            if (isDataRepoTest) {
                context.'annotation-config'()
            }

            proxyHandler(DefaultProxyHandler)
            messageSource(StaticMessageSource)
            transactionManagerAwarePostProcessor(TransactionManagerPostProcessor)
            grailsPlaceholderConfigurer(GrailsPlaceholderConfigurer, '${', grailsApplication.config.toProperties())
            mapBasedSmartPropertyOverrideConfigurer(MapBasedSmartPropertyOverrideConfigurer) {
                grailsApplication = grailsApplication
            }
        }
    }

    @Override
    //overriden so we can add in the ConfigDefaults without messing with doWithConfig
    @CompileDynamic
    protected void registerGrailsAppPostProcessorBean(ConfigurableBeanFactory beanFactory) {

        GrailsApplication grailsApp

        Closure doWithSpringClosure = {
            registerBeans(grailsApp)
            executeDoWithSpringCallback(grailsApp)
        }

        Closure customizeGrailsApplicationClosure = { grailsApplication ->
            grailsApp = grailsApplication
            def cfg = grailsApplication.config
            //Add the defaults in
            cfg.putAll(ConfigDefaults.getConfigMap(false))
            //fire closure if its used
            if (doWithConfig) {
                //call the closure
                doWithConfig.call(cfg)
            }
            // reset flatConfig
            grailsApplication.configChanged()

            Holders.config = grailsApplication.config
        }

        ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues()
        constructorArgumentValues.addIndexedArgumentValue(0, doWithSpringClosure)
        constructorArgumentValues.addIndexedArgumentValue(1, includePlugins ?: DEFAULT_INCLUDED_PLUGINS)

        MutablePropertyValues values = new MutablePropertyValues()
        values.add('localOverride', localOverride)
        values.add('loadExternalBeans', loadExternalBeans)
        values.add('customizeGrailsApplicationClosure', customizeGrailsApplicationClosure)

        RootBeanDefinition beandef = new RootBeanDefinition(TestRuntimeGrailsApplicationPostProcessor, constructorArgumentValues, values)
        beandef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
        beanFactory.registerBeanDefinition("grailsApplicationPostProcessor", beandef)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy