How to insert int into #Value annotation from .yml properties? - spring

Hey guys I am trying to insert a configurable variable from my properties file into the #Transactional method, which is accepting an integer.
This what I did seems like this:
I would like to insert a configurable #Value = ("${TIMEOUT_TIMER}") from the properties instead of this final class variable.
Any ideas?

Create the class variable
#Value("${TIMEOUT_TIMER}")
private Integer timeOutTimer;
And then just use that variable in the #Transactional annotation like you're doing right now.
It would look like
public class Test {
#Value("${TIMEOUT_TIMER}")
private Integer timeOutTimer;
#Transactional(timeout = timeOutTimer)
public void yourMethod() {
}
}

Related

Spring inject environment variable value into a custom class (not String class)

Does anyone know how to inject environment variable to a custom class?
For example, I know #Value can be used to inject to a String class from environment variable or properties file
suppose I want to do the following:
// I want to inject region as US in environment variable
#value("${some_property}")
private static Region region;
Region class looks like:
public class Region {
public static final Region US = new Region("US");
private final String key;
public Region(String key) { this.key = key }
...
}
I tried this way, but at runtime it gives me null value
Most of the time, your environment variable is not an object but just a simple variable like this :
public class Region {
#value("${region.local}")
private String local;
}

#Value In Spring MVC is not getting populated

I am trying to populate an attribute using the #Value annotation in Spring MVC, and it is not getting populated.
I am trying to access the attribute using Struts2 JSP property. my use case looks like that:
public class TransferCreditsAction extends StudentAwareAction {
protected Log logger = LogFactory.getLog(this.getClass());
#Value( "${transfer.credit.url}" )
private String transferCreditUrl;
public void setStates( List<TranslatedValue> states ) {
this.states = states;
}
#Value( "${transfer.credit.url}" )
public String getTransferCreditUrl() {
return transferCreditUrl;
}
}
My property file looks like:
transfer.credit.url
I am accessing this attribute using JSP which looks like:
<s:property value='transferCreditUrl'/>"
I know for a fact that my JSP can access this field, because I tested it when I have this field set for a default value.
However, this field is not getting populated from my property file. I am using Spring 4.1.6
Any help is really appreciated.
Spring can only inject values in its own managed spring beans. That means your TransferCreditsAction should be a spring bean.
There are various ways to declare your TransferCreditsAction class as a spring bean, already answered elsewhere.
You haven't added whats on top of TransferCreditsAction class.
Values will be injected in a Bean Env.
There are many ways of Doing it
Assuming my property file contains
username=Ashish
app.name=Hello
1.
#Service
#PropertySource(value = { "classpath:sample.properties" })
public class PaloAltoSbiClientImpl implements PaloAltoSbiClient {
public static String username;
#Value("${username}")
public void setUrl(String data) {
username = data;
}
...
2.
#Service
public class PaloAltoSbiClientImpl implements PaloAltoSbiClient {
#Value("${username}")
public static String username;
...
3.
#Component
public class TokenHelper {
#Value("${app.name}")
private String APP_NAME;
Just give the properties file reference on top of the class in which you are trying to get.
#PropertySource(value = { "classpath:sample.properties" })
This issue was happening because I was missing <context:annotation-config/> in my applicationContext. Once I added it, it start working with no issues.

How can I use a local variable in the annotation #Preauthorize?

i need to do something like this
String myVar = "myString";
...
#Preauthorize("customMethod(myVar)")
public void myMethod() {
...
}
but I'm failing at it. How can I do that? It says it cannot be resolved
EDIT:I'm decoupling few rest services and sometimes I have to share infos between them
#Value("${my-properties}")
String urlIWantToShare;
...
#PreAuthorize("isValid(#myValue,urlIWantToShare)")
#RequestMapping(value = "**/letsCheckSecurityConfig", method = RequestMethod.GET)
public boolean letsCheckSecurityConfig(#RequestHeader(name = "MY-VALUE") String myValue)) {
return true;
}
this "isValid" custom security method will call an external service, that doesn't know anything about the caller and his infos. I need to transmit few infos and I need to take them from different kind of sources
One of the sources is my application.properties
EDIT2: I managed to do this
#PreAuthorize("isValid(#myValue, #myProperty)")
#RequestMapping(value = "**/letsCheckSecurityConfig", method = RequestMethod.GET)
public boolean letsCheckSecurityConfig(#RequestHeader(name = "MY-VALUE") String myValue,
#Value("${my-property-from-app-properties}") String myProperty))
..but I want to use not only actual static properties but runtime one. Any help?
You can create a wrapper method without parameters which will call the desired method with parameters. In the annotation you can use the method without parameters
Apologies if I have misunderstood what you are trying to do, but from my understanding you're trying to set an annotation at runtime based on a variable / app.properties, so that you can then read this variable and then execute your class?
If this is the case, You cannot do this from an annotation alone as annotations cannot read local variables and cannot be set at runtime.
However, one option for you is to have an object which contains the 'values' of interest for you and then read the values from the object.
Something like the below:
PoJo
public class testObject{
#test
private String myVar;
private String myValue;
//Getters and Setters
}
Get Object values
public void getFields (Object obj){
Field fields = obj.getClass().getDeclaredFields();
for (Field f : fields){
test fieldAnnotation = f.getAnnotation(test.Class);
if (fieldAnnotation != null){
f.get(obj);
// Do checks based on this
}
}
}
Main Class
public static void main(String[] args){
//Create object
testObject test = new testObject();
test.setOne("testOne");
test.setTwo("testTwo");
getFields(test);
}
I've pulled this code based on what I had to do to get the fields - but in my case, I did not know the object types I was going to be passed. You are simply using the annotation to 'mark' the fields you want to retrieve and then reading the value from the object.
If you're in a similar situation, then you can see my answer here: initial answer
Let me know if i've misunderstood this and I can try and further clarify my answer.

How do I mock an autowired #Value field in Spring with Mockito?

I'm using Spring 3.1.4.RELEASE and Mockito 1.9.5. In my Spring class I have:
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Value("#{myProps['default.password']}")
private String defaultrPassword;
// ...
From my JUnit test, which I currently have set up like so:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
I would like to mock a value for my "defaultUrl" field. Note that I don't want to mock values for the other fields — I'd like to keep those as they are, only the "defaultUrl" field. Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
Given this, how can I mock a value for that one field?
You can use the magic of Spring's ReflectionTestUtils.setField in order to avoid making any modifications whatsoever to your code.
The comment from Michał Stochmal provides an example:
use ReflectionTestUtils.setField(bean, "fieldName", "value"); before invoking your bean method during test.
Check out this tutorial for even more information, although you probably won't need it since the method is very easy to use
UPDATE
Since the introduction of Spring 4.2.RC1 it is now possible to set a static field without having to supply an instance of the class. See this part of the documentation and this commit.
It was now the third time I googled myself to this SO post as I always forget how to mock an #Value field. Though the accepted answer is correct, I always need some time to get the "setField" call right, so at least for myself I paste an example snippet here:
Production class:
#Value("#{myProps[‘some.default.url']}")
private String defaultUrl;
Test class:
import org.springframework.test.util.ReflectionTestUtils;
ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}",
// but simply the FIELDs name ("defaultUrl")
You can use this magic Spring Test annotation :
#TestPropertySource(properties = { "my.spring.property=20" })
see
org.springframework.test.context.TestPropertySource
For example, this is the test class :
#ContextConfiguration(classes = { MyTestClass.Config.class })
#TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {
public static class Config {
#Bean
MyClass getMyClass() {
return new MyClass ();
}
}
#Resource
private MyClass myClass ;
#Test
public void myTest() {
...
And this is the class with the property :
#Component
public class MyClass {
#Value("${my.spring.property}")
private int mySpringProperty;
...
I'd like to suggest a related solution, which is to pass the #Value-annotated fields as parameters to the constructor, instead of using the ReflectionTestUtils class.
Instead of this:
public class Foo {
#Value("${foo}")
private String foo;
}
and
public class FooTest {
#InjectMocks
private Foo foo;
#Before
public void setUp() {
ReflectionTestUtils.setField(Foo.class, "foo", "foo");
}
#Test
public void testFoo() {
// stuff
}
}
Do this:
public class Foo {
private String foo;
public Foo(#Value("${foo}") String foo) {
this.foo = foo;
}
}
and
public class FooTest {
private Foo foo;
#Before
public void setUp() {
foo = new Foo("foo");
}
#Test
public void testFoo() {
// stuff
}
}
Benefits of this approach: 1) we can instantiate the Foo class without a dependency container (it's just a constructor), and 2) we're not coupling our test to our implementation details (reflection ties us to the field name using a string, which could cause a problem if we change the field name).
You can also mock your property configuration into your test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
#Configuration
public static class MockConfig{
#Bean
public Properties myProps(){
Properties properties = new Properties();
properties.setProperty("default.url", "myUrl");
properties.setProperty("property.value2", "value2");
return properties;
}
}
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Test
public void testValue(){
Assert.assertEquals("myUrl", defaultUrl);
}
}
I used the below code and it worked for me:
#InjectMocks
private ClassABC classABC;
#Before
public void setUp() {
ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}
Reference: https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/
Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
One way to resolve this is change your class to use Constructor Injection, that can be used for testing and Spring injection. No more reflection :)
So, you can pass any String using the constructor:
class MySpringClass {
private final String defaultUrl;
private final String defaultrPassword;
public MySpringClass (
#Value("#{myProps['default.url']}") String defaultUrl,
#Value("#{myProps['default.password']}") String defaultrPassword) {
this.defaultUrl = defaultUrl;
this.defaultrPassword= defaultrPassword;
}
}
And in your test, just use it:
MySpringClass MySpringClass = new MySpringClass("anyUrl", "anyPassword");
Whenever possible, I set the field visibility as package-protected so it can be accessed from the test class. I document that using Guava's #VisibleForTesting annotation (in case the next guy wonders why it's not private). This way I don't have to rely on the string name of the field and everything stays type-safe.
I know it goes against standard encapsulation practices we were taught in school. But as soon as there is some agreement in the team to go this way, I found it the most pragmatic solution.
Another way is to use #SpringBootTest annotation properties field.
Here we override example.firstProperty property:
#SpringBootTest(properties = { "example.firstProperty=annotation" })
public class SpringBootPropertySourceResolverIntegrationTest {
#Autowired private PropertySourceResolver propertySourceResolver;
#Test
public void shouldSpringBootTestAnnotation_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
Assert.assertEquals("annotation", firstProperty);
Assert.assertEquals("defaultSecond", secondProperty);
}
}
As you can see It overrides only one property. Properties not mentioned in #SpringBootTest stay untouched. Therefore, this is a great solution when we need to override only specific properties for the test.
For single property you can write it without braces:
#SpringBootTest(properties = "example.firstProperty=annotation")
Answer from: https://www.baeldung.com/spring-tests-override-properties#springBootTest
I also encourage you to whenever possible pass property as a parameter in constructor like in Dherik answer (https://stackoverflow.com/a/52955459/1673775) as it enables you to mock properties easily in unit tests.
However in integration tests you often don't create objects manually, but:
you use #Autowired
you want to modify property used in a class that is used in your integration test indirectly as it is deep dependency of some directly used class.
then this solution with #SpringBootTest might be helpful.

Spring: How to inject a value to static field?

With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}

Resources