In one of my classes there is a public static String member and I need set this value in the applicationContext.xml! That is, is it possible for us to inject a value for this static property?
yes there is an example on this link http://planproof-fool.blogspot.com/2010/03/spring-setting-static-fields.html
No, it's not possible to inject a value to a static field from your XML context.
If you can modify the class, you have the following simple choices:
remove the static modifier and add #Inject/#Autowire above the field
add a constructor/setter/init method.
Else, you can do it with Spring's Java configuration support.
An example:
The Demo class with the static field and a JUnit method that asserts that the Spring container injects the wanted value into the static field:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("test-context.xml")
public class Demo {
public static String fieldOne;
#Test
public void testStaticField() {
assertEquals("test", fieldOne);
}
}
Add the context namespace to your applicationContext and component-scan element:
<context:component-scan base-package="com.example" />
Add your bean with the static field like the this:
#Configuration
public class JavaConfig {
#Bean
public Demo demo() {
Demo.fieldOne = "test";
return new Demo();
}
}
In this case, the JavaConfig class must be in the com.example package as declared in the component-scan element.
Related
I've got several #Configuration classes which do specify custom #ConfigurationProperties("sample") and are used within to instantiate several beans that are going to be used my business logic classes later on.
However, I've been trying to do this approach with an inner #Component class so I don't need to fit that within an existing specific or generic config and see what happens.
#Component
#ConfigurationProperties("myclass")
public class MyClass {
private String attribute;
(Constructor, getters and setters for attribute and other methods...)
}
And within my application.properties file I do specify that attribute value as myclass.attribute=value.
Doing it this way results in a null value everytime. Do #Component accept reading .properties file or should it still be in a #Configuration class?
I should have put it as a comment. But didn't want someone to miss this trivial thing.
Okay the issue is - You are missing the '$' (DOLLAR SYMBOL). Wondering why nobody noticed it?
In your properties file if you have this :
myclass.attribute=value
Then to access it in any class, do this:
#Value("${myclass.attribute}")
Noticed the $ symbol above??
Everything is working as expected, even using #ConfigurationProperties in class annotated with #Component. Please try :
application.properties :
myclass.attribute=value
MyClass class :
#Data
#Component
#ConfigurationProperties("myclass")
public class MyClass {
private String attribute;
}
Test class :
#RunWith(SpringRunner.class)
#SpringBootTest
public class FooTests {
#Autowired
private MyClass myClass;
#Test
public void test() {
System.out.println(myClass.getAttribute());
}
}
You do need the #EnableConfigurationProperties annotation on on of you configuration classes, eg the application class.
#SpringBootApplication
#EnableConfigurationProperties
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class);
}
}
I've never used the #ConfigurationProperties annotation but if you want to set your attribute from a value in your application.properties I'll recommend using the #Value annotation :
application.properties :
myclass.attribute=foo
#Component
public class MyClass {
#Value("myclass.attribute")
private String attribute;
// ...
}
This way every instance of MyClass will have attribute with the default value foo
I want to let Spring assign a property value.
public class Foobar {
#Value("${example.property.foo:bar}")
private String foo;
}
Let's say I want to refer to example.property.foo in several different places, so I'd rather assign the flag as a constant on Foobar:
public class Foobar {
public static final String FOO_PROPERTY_FLAG = "example.property.foo";
}
The setting of example.property.foo=whatever happens elsewhere (as a system property, or in a #TestPropertySource).
How can I refer to FOO_PROPERTY_FLAG in the annotation? This works:
#Value("${" + FOO_PROPERTY_FLAG + ":bar}")
But it's kind of ugly. Can I use the "#{}" expression syntax here somehow?
#Value("${#{FOO_PROPERTY_FLAG}:bar}") // doesn't work; value is never injected
You can do something like:
public static final String KEY = "propertyName";
#Value("#{T(a.b.c.package.MyConstants).KEY}")
The important part is to specify package and class. Otherwise spring will try to lookup constant in BeanExpressionContext which is actually executing your SpEL
private #Value("${propertyName}") String propertyField;
No getters or setters!
With the properties being loaded via the config:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:propertyFile.properties" name="propertiesBean"/>
There's also the totally non-Xml version:
#PropertySource("classpath:propertyFile.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Make sure and add in the namespace URI xmlns:p="springframework.org/schema/p"; to use the p: prefixed attributes
For one of my Spring beans(say Application class), I'm fetching the value of a property(my.property.flag=true/false) from a properties file(prop.properties) using #Value annotation. That works perfectly fine.
I need to write an integration test(say ApplicationIt class) where I need to test with both the values of the property i.e. for both true and false.
In my properties file, the value of the property is set to true. Is it possible to set the value dynamically to false from my Integration test?
For Example,
prop.properties:
my.property.flag=true
Application class file:
#Component
class Application {
//This value is fetched from properties file
//the value is set to true.
#Value(${my.property.flag})
private String isTrue;
......
..........
}
Integration Test:
class ApplicationIT {
//how can I set the value of isTrue here to false?
}
You can specify test properties on the test class as follows:
#RunWith(SpringRunner.class)
#TestPropertySource(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
public class MyTest {
Since Spring has a whole hierarchy of property overrides, this works pretty well, the downside being you need separate test classes for different values. If you're using Spring Boot, there's another annotation that provides the same functionality but also has more options for configuring your test environment. Example:
#SpringBootTest(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
Again, you will need separate test classes to handle hard-coded test properties.
I was bugged with this for a while and found this neat way to override the properties. It is quite useful if you need some programmatic initialization of the application context such as registering property sources like in that case but not only. The following approach uses ContextConfiguration's initializers.
example for Spring Boot 1.5.x :
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
#ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
#DirtiesContext
public abstract class AbstractIntegrationTest {
private static int REDIS_PORT = 6379;
#ClassRule
public static GenericContainer redis = new GenericContainer("redis:3.0.6").withExposedPorts(REDIS_PORT);
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ctx) {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(ctx,
"spring.redis.host=" + redis.getContainerIpAddress(),
"spring.redis.port=" + redis.getMappedPort(REDIS_PORT));
}
}
}
example for Spring Boot 2.x :
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
#ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
#DirtiesContext
public abstract class AbstractIntegrationTest {
private static int REDIS_PORT = 6379;
#ClassRule
public static GenericContainer redis = new GenericContainer("redis:3.0.6").withExposedPorts(REDIS_PORT);
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ctx) {
TestPropertyValues.of(
"spring.redis.host:" + redis.getContainerIpAddress(),
"spring.redis.port:" + redis.getMappedPort(REDIS_PORT))
.applyTo(ctx);
}
}
}
I want to mention good old reflection way. You can use spring provided utility class for it after you wired in your component:
ReflectionTestUtils.setField(component, "isTrue", true)
You can change it to any value you want in consequent tests
Preferably, use constructor injection instead of field injection:
#Component
class Application {
Application(#Value("${my.property.flag}") boolean flag) {
...
}
}
This makes using mocks or test values as simple as passing an argument.
I'm new to Java Spring and trying to use Java configuration and inject a dependency into a class constructor. I want to use constructor injection because the class methods require the dependency. It isn't working for me.
Use case: Create a JSON string from a Java object and validate it before returning.
Class: FakeJsonBuilder
Dependency: JsonValidator
Main class: Per Spring documentation the #SpringBootApplication annotation is a convenience annotation that adds #Configuration, #EnableAutoConfiguration and #ComponentScan so I should be good to go as far as dependency injection is concerned.
#SpringBootApplication
public class MySpringApplication {
public static void main(String[] args){
// Register the class we use for Java based configuration
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.register(ApplicationConfiguration.class);
context.refresh();
SpringApplication.run(MySpringApplication .class, args);
}
}
Java configuration class:
#Configuration
public class ApplicationConfiguration {
#Bean
public JsonValidator jsonValidator(){
return new JsonValidatorImpl();
}
#Bean
public JsonBuilder(){
return new FakeJsonBuilder();
}
}
FakeJsonBuilder class:
public class FakeJsonBuilder implements JsonBuilder{
private static Log logger = LogFactory.getLog(FakeJsonBuilder.class);
private static JsonValidator jsonValidator;
// I need an empty constructor for the ApplicationConfiguration setup to work.
public MlrModelJsonBuilder(){};
#Autowired
public FakeJsonBuilder (JsonValidator jsonValidator){
this.jsonValidator = jsonValidator;
boolean validatorInjected = (jsonValidator != null);
logger.info("Validator injected: " + validatorInjected);
}
.......... More methods
The jsonValidator dependency is not being injected, i.e. the log message is Validator injected: false
Quoting Martin: Fowler http://martinfowler.com/articles/injection.html
"My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations."
I come from a .NET background and use Ninject to inject my dependencies into the class constructor for the reasons Fowler gives. I quoted Fowler because of his credibility but you will find many sources providing the same argument, i.e. if the class methods require the dependency then it should be injected into the constructor. So here's how I figured how to do it with Java Spring (I revert to my C# syntax - forgive the transgression):
The configuration class
#Configuration
public class ApplicationConfiguration {
#Bean
public IJsonValidator jsonValidator(){
return new JsonValidator();
}
#Bean
public IJsonBuilder jsonBuilder(){
return new JsonBuilder(jsonValidator());
}
}
The class into which we inject the dependency
public class JsonBuilder implements IJsonBuilder {
private static IJsonValidator _jsonValidator;
// #Autowired // not needed per Sotirios. tested and verified
public JsonBuilder(IJsonValidator jsonValidator) {
_jsonValidator = jsonValidator;
}
public String getFoobar() {
// Returns false. jsonValidator was injected
boolean foo = (_jsonValidator == null);
return "Validator was injected: " + foo;
}
... more methods
I am studying for the Spring Core certification and I have the following doubt related how can Spring instantiate classes with private constructors (such as Singleton pattern) or how can instantiate objects from Factories (that are not the Spring context).
For example I have the following singleton factory:
public class AccountServiceSingleton implements AccountService {
private static AccountServiceSingleton inst = new AccountServiceSingleton();
private AccountServiceSingleton() { ... }
public static AccountService getInstance() {
// ...
return inst;
}
}
This is a singleton factory because it build a private static object builded with a private constructor and I have a public method to get this object.
So I think that the problem how can Spring build this object? depends on the fact that that the constructor is private so I can't do something like this in my Java configuration class
#Confguration
public class ApplicationConfig{
#Bean
public AccountServiceSingleton accountServiceSingleton(){
return new AccountServiceSingleton();
}
}
because I can't access to the private AccountServiceSingleton() constructor.
At the same time I can't use the equivalent XML configuration for the same reason.
Have I understand what is the problem or am I missing something?
I think that I am missing something because on the documentation I read that I can use the following 2 solutions for the previous problem:
Use a #Bean method in #Configuration class: so, reading it, I think that the previous Java configuration class work...but why?
XML factory-method attribute in the XML configuration, searching online I found that have to be something like this, but how can I use this to configure the previous AccountServiceSingleton bean in an XML configuration?
Tnx
It's really easy, and you can do it, too:
Constructor cxor = AccountServiceSingleton.class.getDeclaredConstructor();
cxor.setAccessible(true);
return cxor.newInstance();
I found the answer by myself still reading the documentation. I think that the right answer for the question is:
If I want to configure this class as a Spring bean:
public class AccountServiceSingleton implements AccountService {
private static AccountServiceSingleton inst = new AccountServiceSingleton();
private AccountServiceSingleton() { ... }
public static AccountService getInstance() {
// ...
return inst;
}
}
using the Java configuration I simply have to annotate the relative bean method using #Bean in the configuration class.
If I want configure the beans using the XML configuration I have to use the factory method attribute, something like it:
<bean id=“accountService” class=“com.acme.AccountServiceSingleton”
factory-method="getInstance" />
So it say that the getInstance() method will be call to obtain the singleton object from my singleton factory
How about doing like this:
#Confguration
public class ApplicationConfig{
#Bean
public AccountServiceSingleton accountServiceSingleton(){
return AccountServiceSingleton.getInstance();
}
}