Overzealous auto-wiring of spring bean properties in grails - spring

I have a domain class:
class Searcher {
String names
List<String> getExperiments() {
return names.split(',');
}
void setExperiments(List<String> list) {
names = list.join(',');
}
}
and a bean defined in the resource file
experiments(com.fxpal.querium.experiment.ExperimentHolder) {
otherProp = 'foo'
}
The experiments bean is semantically different from the experiments property of the Searcher class.
How do I prevent Spring from auto-wiring a specific property of a specific bean? Since the experiments property of the Searcher bean is derived, I don't want Spring to touch it at all.

Why not just name your bean experimentHolder? By default its going to auto wire by name.

Related

spring boot component with string parameters

i have a component that reads a configuration value from application.properties and accepts a string parameter in its constructor as such..
#Component
public class Person
{
#Value("${greeting}")
String greeting;
String name;
public Person(String name)
{
this.name = name;
onGreet( greeting + ", " + name );
}
public void onGreet(String message)
{
}
}
I need to instantiate this component as follows and override its "onGreet" event in the calling code as follows:
Person jack = new Person("jack")
{
public void onGreet(String message)
{
System.out.println( message );
}
};
However I end up getting this..
Parameter 0 of constructor in demo11.Person required a bean of type 'java.lang.String' that could not be found.
My application.properties is as follows:
greeting=hello
What am I missing here? Thank you.
It is literally telling you that the only constructor that you have requires a parameter that Spring knows nothing about.
Add a #Value to that String name in the constructor (right before the parameter) like so public Person(#Value("${name}") String name) if you want Spring to initalize it or remove that constructor
EDIT: some more explanation:
Spring is a dependency injection container. Meaning you define beans and let Spring create and inject them for you. Defining beans can be done in several ways (Java configuration, annotations or xml) here you are using annotation way via #Component.
Now that you have defined your bean (aka component) for Spring it will create it. For it to create it it needs to call a constructor. For that you need to provide it with all information necessary for constructor call - meaning all parameters. If parameters are other classes they need to be defined as beans as well (For example via #Component) if they are simple types like String you need to provide #Value for them.
Lastly if you ever use new ... to define Spring managed beans then the whole Spring magic disappears since Spring doesnt know about this bean instantiation anymore and will not autowire anything into it. For all intenses and purposes Spring is not aware of any objects you create with new.

Grails DataBindingListener not hearing binding events

I added a class in src/groovy that implements the DataBindingListener interface. My init/Application file registers the Spring bean in the doWithSpring method
#Override
Closure doWithSpring() {
def beans = {
applicationBindingListener(org.mkv.ApplicationBindingListener)
}
return beans
}
I confirmed the bean is registered. However it doesn't seem to be receiving any of the binding events.
I'm using grails 4.0.0
In my case, I edit config/spring/resources.groovy. It's the source.
beans = {
dataBindingListener org.mkv.ApplicationBindingListener
}
And, The code below is added as a test case method to ensure that the bean configured in the test code is used.
boolean loadExternalBeans() {
true
}

how to load config in spring-webflux without spring-boot?

I just take some experiments with spring webflux 5.0.0 and Kotlin, and I have problem with loading configuration from application.yml
For base project I start with this example spring-kotlin-functional
But there are only manual loading beans and routing without any loading from configuration files or example how to implement analog of #ConfigurationProperties class in such way.
I have try to take environment in beans section:
data class DbConfig(
var url: String = "",
var user: String = "",
var password: String = ""
)
fun beans(): BeanDefinitionDsl = beans {
bean {
//try to load config from path=db to data class DbConfig
env.getProperty("db", DbConfig::class.java)
}
bean<DBConfiguration>()
//controllers
bean { StatsController(ref()) }
bean { UserController(ref()) }
//repository
bean { UserRepository(ref()) }
//services
bean { StatsService(ref()) }
//routes
bean { Routes(ref(), ref()) }
bean("webHandler") {
RouterFunctions.toWebHandler(ref<Routes>().router(), HandlerStrategies.builder().viewResolver(ref()).build())
}
//view resolver
bean {
val prefix = "classpath:/templates/"
val suffix = ".mustache"
val loader = MustacheResourceTemplateLoader(prefix, suffix)
MustacheViewResolver(Mustache.compiler().withLoader(loader)).apply {
setPrefix(prefix)
setSuffix(suffix)
}
}
}
but there are only system properties in Environment
So the question is how to load configuration from application.yml and how to implement analog of #ConfigurationProperties in such functional style?
And do I understand correctly that without spring-boot all annotations (like #Bean, #Repository, #Transactional and other) will not work for Beans?
My sources: github
Update 2017-10-21
Find a solution. The problem was related to the fact that there there were no any BeanPostProcessor. And after I include this two processors:
bean<CommonAnnotationBeanPostProcessor>()
bean<ConfigurationClassPostProcessor>()
annotations #Configuration,#Bean and #PostConstruct start to work. But annotation #ConfigurationProperties exists only in spring-boot dependency, and yml parsing classes I find only in spring-boot-starter..
After including dependency spring-boot-starter and adding bean<ConfigurationPropertiesBindingPostProcessor>() to beans section, annotation #ConfigurationProperties start to work, but config from application.yml was also not included. So I add this section:
val resource = ClassPathResource("/application.yml")
val sourceLoader = YamlPropertySourceLoader()
val properties = sourceLoader.load("main config", resource, null)
environment.propertySources.addFirst(properties)
to GenericApplicationContext configuration. And now all work as I expect, but with including a dependency spring-boot-starter.
Full code sample: version with fixes
Spring boot is just a dependency management that build auto-configuration that you can override.
All the feature are inherited from Spring framework and modules. So basically you could do the same with or without boot.
I'm not on webflux yet. But as you reference your other beans, you mat need to declare a configuration bean elsewhere.
I'm sure I'll help you with that...

Grails 2.4.2 bean spring bean injection

Sample app located here : https://github.com/rushidesai1/Grails2_4_2_BeanIssue
Question:
In resources.groovy if we declare a bean like this
beans = {
testObject(TestObject){bean ->
bean.scope = "prototype"
map = new HashMap() // or [:]
//And also if we declare any object like this
testA = new TestA()
}
}
and Now if we DI testObject bean or do 'Holders.grailsApplication.mainContext.getBean("testObject")', then the bean we get will have singleton 'map' and singelton 'testA' object.
Here testObject is declared as 'prototype' and even then both 'map' and 'testA' are singleton
I want to know if this is a bug or it is working as designed. It is completely counter intuitive that it would work like this since we are specifically doing new and so we expect a new bean being injected everytime.
Use the Unit test case to see more detailed version of my question.
Thanks in advance for clarification !!!
I want to know if this is a bug or it is working as designed.
Yes, I think it is working as designed.
Your testObject bean is a singleton. That singleton bean only has 1 copy of the map and testA properties. The behavior you are describing is exactly what I would expect.
EDIT:
I have reviewed the application in the linked project and this is what is going on...
In resources.groovy you have something like this:
testObject(TestObject) { bean ->
bean.scope = "prototype"
mapIssue1 = ["key1FromResource.groovy": "value1FromResource.groovy"]
}
That testObject bean is a prototype scoped bean so each time you retrieve one, you will get a new instance. However, you have the initialization Map hardcoded in the bean definition so the bean definition that is created has that Map associated with it so every bean created from that bean def will have the same Map. If you want a different Map instance, you could create it in afterPropertiesSet or similar.
The unit test at https://github.com/rushidesai1/Grails2_4_2_BeanIssue/blob/e9b7c9e70da5863f0716b998462eca60924ee717/test/unit/test/SpringBeansSpec.groovy is not very well written. Seeing what is going on relies on interrogating stdout after all of those printlns. The behavior could be more simply verified with something like this:
resources:groovy
import test.TestObject
beans = {
testObject(TestObject) { bean ->
bean.scope = "prototype"
mapIssue1 = ["key1FromResource.groovy":"value1FromResource.groovy"]
}
}
SpringBeansSpec.groovy
package test
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
#TestMixin(GrailsUnitTestMixin)
class SpringBeansSpec extends Specification {
static loadExternalBeans = true
void 'test bean properties'() {
setup:
def testObject1 = grailsApplication.mainContext.testObject
def testObject2 = grailsApplication.mainContext.testObject
expect: 'test TestObject beans are not the same instance'
!testObject1.is(testObject2)
and: 'the TestObject beans share values defined in the bean definition'
testObject1.mapIssue1.is(testObject2.mapIssue1)
}
}
On one hand it might be confusing that even if you are using new it should be creating a new Object each time you get testA bean and on the other hand it is working as expected. How?
Alright! So the answer lies in Spring java Configuration. The resources.groovy is using DSL which internally is a Configuration file.
Not sure if you know or remember about springs #Configuration annotation. Using this we are making POJO a configuration file.
Now the rules of Spring are:
Any bean created is singleton by default until unless specified.
Even if you are using new in java configuration file. Spring is made wise enough that it is a spring config file and hence new doesn't mean a new Object always.
Hence, for equivalent configuration file if I skip testObject and map for now is below:
#Configuration
public class JavaConfiguration {
#Bean
public Teacher teacher(){
TestA testA = new TestA();
return teacher;
}
}
Here, we have used new TestA(). But spring will always return same object until you specify explicitly to use scope Prototype.
Hence, above Configuration file would be like below after enabling prototype scope:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
#Configuration
public class JavaConfiguration {
#Bean
#Scope(value="prototype")
public Teacher teacher(){
TestA testA = new TestA();
return teacher;
}
}
and corresponding DSL would be:
testA(TestA){bean->
bean.scope='prototype'
}
Hope it helps!!

proper way to use getBean() to create Beans dynamically

Setup :
- have a Several Configuration Class containing Bean definitions for my beans
- I will fetched a List of String from a database containing all the bean names and their corresponding Configuration class I want to instantiate dynamically
currently I will do a loop on the list and then call a method passing the beanName and the Configuration Class containing the bean definition:
private Object getBean(String beanName, Class configurationClass) {
Object bean = null;
AbstractApplicationContext context = new AnnotationConfigApplicationContext(
configurationClass);
bean = context.getBean(beanName);
return bean;
}
I would then use the returned object and used Reflections to invoke specific Methods based on a list I fetched from a database.
Question : Is there a proper way to do this ? because for every bean I want to create , I think performance will be affected.
You can use this in spring 4.1
I found the below example in this post - Spring MVC: How to return image in #ResponseBody?
public ResponseEntity<InputStreamResource> downloadUserAvatarImage(#PathVariable Long userId) {
GridFSDBFile gridFsFile = fileService.findUserAccountAvatarById(userId);
return ResponseEntity.ok()
.contentLength(gridFsFile.getLength())
.contentType(MediaType.parseMediaType(gridFsFile.getContentType()))
.body(new InputStreamResource(gridFsFile.getInputStream()));
}

Resources