I'm having some trouble using my values from a .properties file.
My my-properties.properties file looks something like this:
email.host=smtp.googlemail.com
email.port=465
Then my Configuration file looks like this:
#Configuration
#PropertySource("classpath:my-properties.properties")
class MyProperties{
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}
And then I'm trying to use it in this Email class:
#Component("MyProperties.class")
public class AutomatedEmail {
private String recipient;
private String fullName;
private String tempPassword;
private Email email;
#Value("email.from")
private String from;
...
public AutomatedEmail(){
}
public AutomatedEmail(final String recipient, final String fullName, final String tempPassword) throws EmailException {
this.recipient = recipient;
this.fullName = fullName;
this.tempPassword = tempPassword;
}
But it is always coming back saying its null. I've also tried an Autowired approach and setting up the entire email object in the MyProperties class, but that is null also after I call my Constructor
You need to surround the name in the properties file with curly brackets and a dollar sign to make a Spring expression.
#Value("${email.from}")
There's more info in this tutorial on spring values
Edit: Note that this will only work if the bean has been instantiated and managed by the Spring container. You won't be able to inject values into the bean if you just call new Email();.
Read through the spring doco on bean IoC to get a better understanding. And a bit more info on how to instantiate beans.
Related
I am using a #Configuration to configure the creation of a RestTemplate bean, that needs some information such as API-key and host etc.
The thing is, I need to be able to make a number of beans, matching a number of API-keys, fetched from a database.
My code right now, looks like this:
#Configuration
public class DandomainProperties {
private String apiKey;
private String host;
private String ordersPath;
private String orderPath;
private String manufacturerPath;
private DanDomainRestTemplate danDomainRestTemplate;
#Bean
DanDomainRestTemplate danDomainRestTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.basicAuthentication("", this.apiKey)
.build(DanDomainRestTemplate.class);
}
So basically, I need to change the configuration and then create a matching RestTemplate bean, any number of times.
As far I as know from your question, you want to create a restTemplate for each individual situation, maybe you could replace an #Configuration bean provider with a Service that provides different kinds of apis?
For example:
#Service
public class DandomainApiProvider {
#Autowired
private ApiRepository apiRepository;
#Autowired
private DanDomainRestTemplate danDomainRestTemplate;
DanDomainRestTemplate restTemplateOf(String queryId) {
// Fetch apikeys from DB by repository
String apiKey = apiRepository.queryApiKey(queryId);
return restTemplateBuilder
.basicAuthentication("", apiKey)
.build(DanDomainRestTemplate.class);
}
With DanDomainRestTemplate your own implementation, and ApiRepository some definition like:
public interfadce ApiRepository {
// Query apiKey by ID
String queryApiKey(String queryId);
}
I'm fairly new to Spring & Spring boot, trying to wrap my head around with the concepts.
I have this sample class, this is just a typed up code to show what i'm trying to do. There are no compilation errors. When I start the server, the MQConnection class code gets executed, the mq properties from the appplication.properties are read and printing. But when another class tries to call the send message to MQ, i'm seeing NUllPointerException
#Component
public class MQConnection {
private String username;
private String password;
private String host;
private Connection connection;
#Autowired
public MQConnection(#value("${username}") String username,
#value("${password}") String password, #value("${host}") String host) {
this.username = username;
this.password = password;
this.host = host;
init();
}
public getConnection() {
return connection
}
private init() {
connection = mqconnection;
System.out.println(username, password, host); // I see the value when the server is started
//code to connect to mq
}
}
What am I missing, these autowired & beans is really confusing for me as i'm new to Spring world. Am I using right flow or completely absurd, I don't know
#Component
public class MQSendMessage {
#Autowired
MQConnection mqConnection;
public void sendMessage(String message) {
connection = mqConnection.getConnection(); //NULL value
//send messageCode throws nullpointerexception
}
}
public class AnotherClass {
#Autowired
MQSendMessage messageq;
public doSomething() {
messageq.sendMessage("hello world");
}
}
Any help to fix the connection that throws nullpointer
It looks like AnotherClass is not instantiated by Spring container. If you want to use Spring-annotation like convention then you have to annotate your class with e.g.#Component annotation. Otherwise Spring wont instantiate this object for you.
Useful tip
Try using constructor injection instead of a field injection. Just like in your MQConnection class. You can even mark all your class fields instantiated in the construct with final keyword so you will be sure that these values wont change (if they are immutable of course) during bean life cycle. Then AnotherClass could look like this:
public class AnotherClass {
private final MQSendMessage messageq;
#Autowired
public AnotherClass(MQSendMessage messageq) {
this.messageq = messageq
}
public doSomething() {
messageq.sendMessage("hello world");
}
}
Spring Boot documentation
Also please read carefully Spring Boot documentation on Spring Beans and dependency injection. It is very well written and describes basic concepts in details. It will make your learning much easier and faster.
I hope it helps.
Spring Boot | MyBatis
When I try to declare a mybatis mapper in controller, it gets underlined by IDE, and doesn't compile.
#Controller
#RequestMapping("demo")
#MapperScan("com.sample.mapper")
public class MessageController {
private static final String MESSAGE = "message";
private static final String INDEX = "index";
#Autowired
private MessageMapper messageMapper;
#RequestMapping("printMessage/{message}")
public String printMessage(ModelMap modelMap) {
modelMap.addAttribute(MESSAGE, "M");
return INDEX;
}
#RequestMapping("printHello")
public String printHello(ModelMap modelMap) {
modelMap.addAttribute(MESSAGE, "Hello, ");
return INDEX;
}
I got this class compiled somehow recently, however, when I try to use messageMapper instance, like messageMapper.insert() as it's not assigned any value, it gives me NullPointerException. It seems like Spring is for some reason is not working for me.
According to the documencation, I think the #MapperScan is not the right class, they cannot be autowired because they are not in the context on controller creation time. When it is defined in Mybatis XML config file, it is loaded with an Sql Session Factory Provider, a place that actually makes more sense, then it shall not be different with annotations style.
I am using Spring MVC for project. I have some constant values which is stored in properties file and I want to fetch from properties file. Question I am unable to fetch values in Model Classes from properties file. It is getting null.
I have set property file location in servlet-context.xml
<context:property-placeholder location="classpath:myproperties.properties" />
Now by using #Value annotation I inject value from properties file.
#Component
class ModelTest {
#Value("${fname}")
private String fname;
// Default Constructor
public ModelTest(){
Sysout(fname); // getting null here
}
#PostConstruct
public void initMembers(){
Sysout(fname) // Prints fname value properly
}
public void setFname(String fname){
this.fname=fname;
}
public String getFname(){
return fname;
}
#Override
public String toString() {
Sysout(fname);
return "ModelTest [variableFirst=" + variableFirst + "]";
}
}
Here is ServiceTest class.
#Service
class ServiceTest(){
#Value("${fname}")
private String fname;
public String printTest(){
sysout(fname); // Prints fname value
return new ModelTest().toString() // Prints null
}
}
Here is ControllerHome Class :
#Controller
public class ControllerHome {
#Value("${fname}")
private String fname;
#Autowired
private ServiceTest service;
#RequestMapping("/")
public #ResponseBody String printData(){
sysout(fname); // Prints fname value
return service.printTest(); // Print null
}
}
In model class fname is getting null while In controller and service class value is coming properly.
is anyone face such issue?
When you say model class, do you mean the value passed to a controller method indicated by #ModelAttribute?
If so, that class is created by ordinary constructor invocation through reflection. It is not a spring bean, and thus #Value does nothing.
Addressing your edit, I think there is some fundamental misunderstanding about how Spring works.
#Service
class ServiceTest(){
#Value("${fname}")
private String fname;
public String printTest(){
sysout(fname); // Prints fname value
// Calling new here means Spring does nothing
// ModelTest is not a Spring bean
// `#Component`, `#PostConstruct` and `#Value` in ModelTest mean nothing.
return new ModelTest().toString() // Prints null
}
}
Instead, you have to do something like this:
#Service
class ServiceTest(){
#Value("${fname}")
private String fname;
#Autowired
private ModelTest modelTest;
public String printTest(){
sysout(fname); // Prints fname value
// modelTest is now a Spring bean
return modelTest.toString() // Should not print null
}
}
Now, Spring will create ModelTest, and #Component, #PostConstruct and #Value will be honored by Spring.
However, #Component by itself has a default singleton scope. So, you will have the same modelTest always.
So, you have to do something like this:
#Component
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
class ModelTest {
// ...
}
Now, while the modelTest reference in ServiceTest will remain constant, the use of a proxy will divert the method calls to a new instance of ModelTest, created by Spring, per request.
This is how I do it :
#Component
#PropertySource("classpath:myproperties.properties") // <-Add this.
class ModelTest {
#Autowired
private Environment env;
public void test(){
String name = env.getProperty("name"); //Assuming you have a 'name' key in your myproperties.property
}
}
What is faster (and better) ? :
Load variables to a special
static object and when a variable
from configuration file is needed
get variale from static object's
field.
Copy configuration
variable to a local field when
creating new object which needs a
configuration variable.
I prefer instance level myself, as long as you aren't doing it excessively (i.e. Don't read the configuration every time you instantiate something).
Static configurations will give you heartache. Especially for testing.
The best solution in my mind is to use a framework like Spring (or Guice) to inject configuration type information into your objects.
I'd say use on-demand caching. Look at the MapMaker from guava-collections. If you doesn't want to add additional dependency then I'd prefer option 1.
I would abstract the configuration with an interface and provide strategies like:
public interface Config {
public String getUrl();
public String getName();
}
public class PropertiesConfig implements Config {
private final String url;
private final String name;
public PropertiesConfig(String filepath) {
Properties props = // read properties from file input stream
this.url = props.getProperty("url", "");
this.name = props.getProperty("name", "");
}
// getters from interface
}
public class SpringConfig {
private final String url;
private final String name;
public SpringConfig(String contextPath) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(contextPath);
this.url = (String) ctx.getBean("url");
this.name = (String) ctx.getBean("name");
}
// getters from interface
}
Etc., you could provide a bunch of strategies obviously.
public class Application {
private final Config config;
public Application(Config config) {
this.config = config;
}
public String doWork() {
return Client.url(config.getUrl()).get();
}
}