I have trouble getting #Value annotations working with a Spring bean in a Grails 2.3.4 app.
I have a separate jar as a Grails dependency. The jar has annotated beans:
#Named
public class Bean {
#Value("${client.environment}")
private String environment;
....
}
I have setup the property in Config.groovy.
...
client.environment = "DEV"
...
When I run Grails in IntelliJ IDEA the property works and the #Value annotated variable is populated automatically. But when I deploy the war to a standalone Jetty instance the same property has not been initialized and its value is instead "${client.environment}".
I have tried for hours to check all production and development settings so they don't change anything. I've also tried multiple solutions to load properties in Grails and even tried to setup a propertyPlaceholderConfigurer in resources.groovy but nothing helps.
The #Value annotation from Spring needs single quotes in order to work (Tested on Grails 4):
import org.springframework.beans.factory.annotation.Value;
public class Bean {
#Value('${client.environment}')
String environment;
...
}
So I got the bean working as inteded by following these instructions. First I read the property from the property file and explicitly set it to the bean variable using the last method in the following URL (using beans in Config.groovy)
http://softnoise.wordpress.com/2013/07/29/grails-injecting-config-parameters/
Related
I started setting tests for my project. It taked a while to settup the context. Now that I have achived it, I am getting trouble to make the tests work on multiple enviroments.
I set up the application test with these anotations:
#ContextConfiguration({"/applicationContext-test.xml", "/appServlet/servlet-context.xml"})
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#AutoConfigureMockMvc
public class ControllerUserTest {}
The trouble comes from the config file. When running the project on enviroments a parent config file values get replaced by environment ones. For testing for some reason I don't find a way to reproduce this. Meanwhile I setted up the parent config file with develop variables. To resolve this, the parent file was restored and using anotations like #TestPropertySource(properties="env=pre") or #ActiveProfiles("pre"). Neither way the parent file variables are replaced by environment ones. This kind of annotationa allows to change profile from class but It would be intereset to change the envoroment it from command line.
I also tried to use #BeforeClass annotation but the context annotations are executed before it.
To add more info about how the config is read. On "/appServlet/servlet-context.xml" I have a component-scan that points to a package where ApplicationConfig.java is stored . This config has this anotations #Configuration #PropertySource(value = { "classpath:nsf.properties" }).
In which direction I have to investigate to achieve my goal? Thanks in advance
I have generated a jhipster monolithic app. I have created a class to connect with the AWS S3 and upload a file there. I defined the properties in .yml file. Here everything works fine.
When I am trying to run the provided tests, most of them are failing with the following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 's3AutoConfig': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.endpoint.url' in value "${aws.endpoint.url}"
S3AutoConfig is the class which uses the properties.
I checked jhipster's documenation and several posts, like the one below:
Adding applicationproperties in Jhipster
which mention that you should provide the properties in the ApplicationProperties class (seems a bit redundant).
I defined the properties also in the java class, but the tests are still failing with the same error above.
How should I define the properties, so they are picked up by the tests? Is it necessary to provide them also in the java class as some posts suggest?
Your implementation cannot work because you are defining Aws class within ApplicationProperties which means that your AWS properties will be prefixed by application, so for example application.aws.endpoint.url which does not match your application*.yml structure and this is why you get this error.
You should extract Aws class and its inner classes to its own file (Aws.java) and use prefix "aws".
Also, it would probably better named as AwsProperties.
#ConfigurationProperties(prefix = "aws", ignoreUnknownFields = false)
public class Aws {
Then the second point about tests is that they are using a different classpath than main class so you should ensure that you define these properties also in src/test/resources/config/application.yml
I am unable to read application.properties value in my project in classes that are injected as a bean from another project. My project is using another project which has classes which needs to read configuration from application.properties.
Mine is a maven project and a spring boot application having application.properties in src/main/resources folder and those properties values are defined in it.
What is it that I am missing that it is unable to read file values? Or is there is any other mechanism for setting these properties for classes loaded via component-scan
Below line of code works fine, it is able to read value from the application.properties:
#PostConstruct
void init() throws ClassNotFoundException, IOException {
System.out.println(context.getEnvironment().getProperty("env.host",
"default value"));
}
Now there is another project which I am using in mine. When loading the classes those beans are getting initialized as dependency of another class, there also it tries to read same value in constants file as
static final String HOST_PROPERTY = "${env.host}";
There this value is not getting initialized to value from applictaion.properties
If you want to get application.properties values,you have to two option.
1) you can autowire Environment class and use its getProperty() method as
#Autowired
Environment env;
env.getProperty("${env.host}");
2)#Value annotation
#Value("${env.host}")
String HOST_PROPERTY;
I have a source project, here are some code
#Configuration
public class AnalyzeSyntaxServiceConfig {
#Bean
public AnalyzeSyntaxService analyzeSyntaxService() {
return new AnalyzeSyntaxService();
}
}
and use it in the source project like this
#Autowired
private AnalyzeSyntaxService analyzeSyntaxService;
it works well
then I package it as a jar file, and add it to the target project as a dependency in pom.xml, and I try to use this above service in the same way
#Autowired
private AnalyzeSyntaxService analyzeSyntaxService;
but it's null, why?
Are the package names different between the source and consuming/dependent code base?
A Spring Boot application will scan from the package the SpringBootApplication is placed in and any child packages.
If you have it within the same project, and your configuration class is structured that it is within the same package or a child package e.g.
com.myapp or com.myapp.configs it will be scanned and picked up.
When importing it to a different project you will need to manually component scan for the configuration via the #ComponentScan annotation and provide it with a package to scan for your configuration.
https://github.com/Flaw101/springbootmixin/tree/example/componentscanning
Because the JacksonConfig.class is in a parent (different) package the ComponentScan does not work. The Application class scans everything in com.darrenforsythe.mixinabstractclass and it's child packages. To make Spring Boot scan the JacksonConfig we have to be explicit and add the #ComponentScan("com.darrenforsythe") to the application.
If you uncomment the #ComponentScan within the MixinasbtractclassApplication the tests then pass again as it will load the JacksonConfig again.
Additionally, I would recommend using constructor. injection this would avoid the Autowired dependency being null and inform you on init of the ApplicationContext rather than at runtime.
Make sure that package in which the class available was scanned. Here is the annotation for that, put this annotation in SpringBoot application class.
#ComponentScan("com.abc.xyz")
Also, see if by any chance the class which has this autowired one is getting instantiated. If that class is instantied then ofcource the autowired ones will be null.
I have a module/jar that I've created and am using as a util library. I created a service in there like so:
#Service
public class PermissionsService { ... }
... where this resides in a package here: com.inin.architect.permissions and in my main application, I'm referencing/loading this jar (i.e. set as a dependency in the maven POM.xml file for the app) like so:
<dependency>
<groupId>com.inin.architect</groupId>
<artifactId>permissions</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
and within the application I want to use that service like:
#Autowired
PermissionsService permissions
In the application's spring setup, I've got this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.inin.generator", "com.inin.architect.permissions" })
public class WebConfig extends WebMvcConfigurerAdapter implements ServletContextAware { }
However when I run my application under tomcat, it complains that there isn't a bean for the PermissionsService: "org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ..."
So, how can I bring over the bean from the lib into my application? Surely there's a way. Do you have to set the library up as a full blown spring MVC application so that this can work? i.e. do you have to have #Configuration and #ComponentScan setup in the lib as well?
You have to scan at least the package containing the class you want to inject. For example, with Spring 4 annotation:
#Configuration
#ComponentScan("com.package.where.my.class.is")
class Config {
...
}
It is the same principle for XML configuration.
Just a note on this, but you could decouple your dependency from spring. In your #Configuration class create
#Bean public PermissionsService permissionsService(){
return new PermissionsService()
}
This will also allow it to be injected. Not that you have to remove your spring annotation, just an option making it potentially usable outside of spring.
Ok - i had exactly the same problem - i wanted to autowire a mongo db repository interface from an external jar.
I could autowire every bean from that jar with using
#SpringBootApplication(scanBasePackages = {"com.myrootpackage"})
However - autowiring the interface always failed with "Could not find blablabla..."
But the interface was in the same package as the beans i could import.
It turned out that searching for the mongo db interfaces is NOT taking the scanBasePackages from the #SpringBootApplication into consideration!
It has to be explicitly configured via
#EnableMongoRepositories(basePackages = {"com.myrootpackage"})
Or you could move the main class "up" so the default searching works also for the mongo interfaces. So i understood the problem and found a solution. But i am still a bit unhappy because i need to configure the same lookup path twice. I find it stupid honestly.
I faced the same issue while scanning other classes from other project dependencies, The scanning solution depends on the type of classes you need to scan as follows:
if they are normal #Component, #Service annotations use
#ComponentScan({"com.mypackge1","com.mypackage2"})
If the type of classes are domain objects based on entities use
#EntityScan("com.mypackge1.domain")
If JPA repository classes
#EnableJpaRepositories(basePackages = {"com.mypackage.repository"})
If Redis repository classes use
#EnableRedisRepositories(basePackages = {"com.mypackage.repository"})
Same for Mongo, etc.
You can import application-context.xml for com.inin.architect.permissions in the following manner inside your main application.
<import resource="classpath:/permissionApplicationContext.xml" />
This will enable you to autowire beans from com.inin.architect.permissions that you have defined.