why properties file can not be imported - java

The properties file is src\main\resources\exam-binary.properties. The content in exam-binary.properties is:
user.post.url=http://localhost:9000/users/newUser
The import class is as below, however, seems that the value can not be imported.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.client.RestTemplate;
import com.ma2oo.model.domain.User;
#Configuration
#PropertySource("classpath:exam-binary.properties")
public class RegisterUser {
private static final RestTemplate restTemplate = new RestTemplate();
#Value("${user.post.url}")
private String registerUrl;
public User Register(final User user) {
System.out.println("url print: " + registerUrl);
return restTemplate.postForObject(registerUrl, user, User.class);
}
}
I have #EnableAutoConfiguration which would cover all classes. And The method which would call RegisterUser is:
#RequestMapping(value = {"/signUp"}, method = RequestMethod.POST)
public ModelAndView signUp(#ModelAttribute("user") User user) {
new RegisterUser().Register(user);
return new ModelAndView("quiz_start");
}
The standard output is:
url print: null
Could anyone help that why #PropertySource does not work ?
Thanks in advance.

The root cause is that the instance of RegisterUser that you are using is not a Spring managed bean. Instead, you created it yourself
new RegisterUser() // spring has no knowledge of it
Why is this class a Configuration class? You seem to be using it as a service. Move the property configuration to a proper #Configuration class, declare a bean of type RegisterUser and use the bean in your #RequestMapping annotated method.

Related

calling method with Rest Template Builder

I created this rest template with the rest template builder and set connection and read timeouts. I need to call this rest template from other methods in the program, but am unsure how to do so. please help, thanks in advance!
//create rest template with rest template builder and set connection and read timeouts #Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofMillis(connectTimeout))
.setReadTimeout(Duration.ofMillis(readTimeout))
.build();
}
// this is an example method that calls rest template, unsure what goes in the parameter section
#Bean
public example example() {
return new restTemplate(what goes here)
);
}
if you have created your customised RestTemplate, you may autowire it any class where you want to call it and use the one. if you more than 1 RestTemplates you can use #Qualifier above RestTemplate Bean and use the same in the calling class.
RestTemplateBuilder is a bean provided by Spring boot. You can inject that into any of your Spring bean classes.
Then you just want to configure your restTemplate at the creation of your Spring bean class and store it as a field. You can do something like below (This is not the one and only way).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
#Configuration
public class MyExampleRestClientConfiguration {
private final RestTemplateBuilder restTemplateBuilder;
#Autowired
public MyExampleRestClient(RestTemplateBuilder restTemplateBuilder) {
this.restTemplateBuilder = restTemplateBuilder;
}
#Bean
public RestTemplate restTemplate() {
return restTemplateBuilder
.setConnectTimeout(Duration.ofMillis(connectTimeout))
.setReadTimeout(Duration.ofMillis(readTimeout))
.build();
}
}
Now in Some other spring bean class, you can simply wire the restTemplate bean and re-use.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
public class MyExampleRestClient {
private final RestTemplate restTemplate;
#Autowired
public MyExampleRestClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
//Now You can call restTemplate in any method
}
You may refer this for more.

Spring Annotations Import Config not called

I am trying to make an application that uses Spring annotations to import the configurations. For this question i narrowed it down to two files. The Startup class:
package core;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
#Slf4j
#Configuration
#Import(ConfigSettings.class)
public class Startup {
public static void main (String args[]) {
log.info("main class");
}
}
and the ConfigSettings
package core;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Slf4j
#Configuration
#ComponentScan({"connections", "filter"})
#PropertySource({"classpath:config/${env.config:dev}.application.properties"})
public class ConfigSettings {
public ConfigSettings() {
log.info("Constructor ConfigSettings");
}
}
I expected the outcome to be:
[INFO]Constructor ConfigSettings
[INFO]main class
But it only shows mainclass. It looks like the constructor of the config settings is not called at all. I expect it to call it because of the import annotation.
Can anyone explain what is going wrong? Thank you in advance!
Your best bet is to make the config class return config object that contains your values. Generally I don't tend to add an all-encompassing config object, but have a config file for each component (database, controllers, etc...).
You can then return the configured object as a bean and let spring inject it. If I were to make a config file for a RestTemplate (as a simple example):
#Service
public class RestClientConfig {
#Value("${your.config.value}")
private String yourValue;
private final RestTemplate restTemplate = new RestTemplate();
#Bean
public RestTemplate restTemplate() {
// Configure it, using your imported values
// ...
return restTemplate;
}
}
However, the main method is outside of the spring container and you won't be able to bootstrap it that way, but with the above method you can call the configured component directly where you need to use it.

How to Autowire repository interfaces in Components in Spring Boot

I am using Spring + Mysql and I can Autowire successfully my classes that extended from PagingAndSortingRepository<T,E> in my RepositoryRestController class.
I can autowire the my repositories in controller below.
package com.fallavi.api.user.controller;
import com.fallavi.api.MyConfig;
import com.fallavi.api.purchase.model.Purchase;
import com.fallavi.api.purchase.repository.PurchaseRepository;
import com.fallavi.api.reader.model.Reader;
import com.fallavi.api.reader.repository.ReaderRepository;
import com.fallavi.api.user.calculator.UserCreditHelper;
import com.fallavi.api.user.exceptions.UserCanNotFindException;
import com.fallavi.api.user.model.UserCreditEnoughModel;
import com.fallavi.api.user.model.UserCreditModel;
import com.fallavi.api.user.repository.UsersRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
#RepositoryRestController
#RequestMapping("/user")
public class UserCreditController {
#Autowired
private ReaderRepository readerRepository;
#Autowired
private UsersRepository usersRepository;
#Autowired
private PurchaseRepository purchaseRepository;
#GetMapping(
value = "/userHasCreditEnough/{reader_id}",
headers = "Content-Type=application/json")
public ResponseEntity<UserCreditEnoughModel> userHasCreditEnough(
#RequestHeader(value = "Authorization") String token,
#PathVariable Long reader_id) {
UserCreditHelper userCreditHelper = new UserCreditHelper();
// Find user ID from authorization code START //
Long userID = usersRepository.getUserIDByAuthToken(token);
if (userID == null) {
throw new UserCanNotFindException();
}
// Find user ID from authorization code END //
// Find user credit START //
List<Purchase> purchaseList = this.purchaseRepository.findByUserID(userID);
Integer userCreditLeft = userCreditHelper.userCreditLeft(purchaseList);
// Find user credit END //
// Find user's credit left for Reader START //
Reader reader = this.readerRepository.findByReaderID(reader_id);
boolean isUserCreditEnough = userCreditHelper.userHasCreditEnough(userCreditLeft, reader);
// Find user's credit left for Reader END //
return ResponseEntity.ok(new UserCreditEnoughModel(isUserCreditEnough, reader.getOnline()));
}
}
Sure I want to seperate all layers as service, repository and Controller it is why I creating a new helper class that is service layer.
#Service
public class UserCreditHelper {
#Autowired
UsersRepository usersRepository;
....some methods...
}
In order to call UserCreditHelper class in I am using ApplicationContext in my controller class sample below.
#RepositoryRestController
#RequestMapping("/user")
public class UserCreditController {
#Autowired
private ReaderRepository readerRepository;
#Autowired
private UsersRepository usersRepository;
#Autowired
private PurchaseRepository purchaseRepository;
#GetMapping(
value = "/userHasCreditEnough/{reader_id}",
headers = "Content-Type=application/json")
public ResponseEntity<String> userHasCreditEnough(
#RequestHeader(value = "Authorization") String token) {
// com.fallavi.api.user.calculator is the package of UserCreditHelper.
ApplicationContext ctx = new AnnotationConfigApplicationContext( "com.fallavi.api.user.calculator" );
return ResponseEntity.ok("test");
}
}
When I tried to request /userHasCreditEnough/{reader_id} endpoint it gives error alltime.
"Error creating bean with name 'userCreditHelper': Unsatisfied dependency expressed through field 'usersRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.fallavi.api.user.repository.UsersRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}",
You should create an interface which will be your service layer. Then inject that interface into the controller and call the desire methods in the desire end point of the controller. From there call the implantation you want from this injected interface.

MappingJackson2JsonView Bean breaks after adding ViewResolverRegistry to SpringWebConfig

RESOLVED - see answer.
I've looked through many similar questions and don't see a similar case right off. Certainly this isn't a unique situation and I'm just missing it?
Update A Spring example I found shows a priority property that may help here, but I have only found the XML example. Question expanded below.
Problem Summary
Two view resolvers appear to be conflicting in my SpringWebMVC application.
Problem Details
I'm work on a web app using Spring 4.0.3-RELEASE and have recently added Jackson to support returning Json from calls to a specific controller. This was working until I added an #Override to my SpringWebConfig for configureViewResolvers. Now my calls to my controller which was serving Json just return the template name which should call the Jackson mapper bean.
The big question
How can I make these two coexist? I have found that I can call:
registry.order(int)
and set it to 9 just to make sure it was last, but it still intercepted the jsonTemplate response from the controller. I don't see a way to set an order for the MappingJackson2JsonView bean. #Bean(order=0), for example, is invalid.
Things Tried
Redacting the ViewResolverRegistry, as expected, produces an error when trying to get mapped jsp views.
javax.servlet.ServletException: Could not resolve view with name 'someView' in servlet with name 'spring-mvc-dispatcher'
As noted in the question statement above, I've tried setting the order on the registry for the ViewResolverRegistry, but this did not help.
I also have tried adding the following to the MappingJackson2JsonView instance, view:
Properties props = new Properties();
props.put("order", 1);
view.setAttributes(props);
But as before, this doesn't prevent the ViewResolverRegistry from intercepting "jsonTemplate" before the Jackson mapper can process it.
I also have changed the load order of the configs in the AppInitializer, the code below has been updated to reflect the new load order, but this also did not help.
Reading through the Spring documentation a bit more, it appears that adding a ContentNegotiationConfigurer is going to be what I need to resolve this and I'm presently looking at how to get this to work in a way that preserves auto mapping the Model returned to the jsonTemplate view. Exapmles I've seen so far use a jsp as a view with specific properties called out, which defeats the purpose of using a Json Mapper.
Configuration
I have multiple config classes defined in my package com.mytest.config.
AppInitializer.java handles adding the *config classes to the context.
package com.mytest.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class AppInitializer implements WebApplicationInitializer {
private Logger logger = LoggerFactory.getLogger(AppInitializer.class);
#Override
public void onStartup(ServletContext container) throws ServletException {
try {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(JSONConfiguration.class);
ctx.register(SpringWebConfig.class);
ctx.setServletContext(container);
container.addListener(new ContextLoaderListener(ctx));
container.addListener(new RequestContextListener());
logger.info("Created AnnotationConfigWebApplicationContext");
ServletRegistration.Dynamic dispatcher = container.addServlet("spring-mvc-dispatcher", new DispatcherServlet(ctx));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
logger.info("DispatcherServlet added to AnnotationConfigWebApplicationContext");
} catch (Exception e) {
logger.error(e.getLocalizedMessage(), e);
}
}
}
SpringWebConfig.java is where I register the majority of my beans.
package com.mytest.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages={"com.mytest.controller","com.mytest.bean","com.mytest.model"})
#PropertySource(value={"classpath:application.properties"})
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Autowired
private Environment env;
private Logger logger = LoggerFactory.getLogger(SpringWebConfig.class);
// bunches of beans such as JdbcTemplate, DataSource... omitted for simplicity
#Override // apparent problem location -- needed for jsp resolving
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/html/",".jsp");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
logger.info("DefaultServletHandlerConfigurer enabled");
}
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new com.honda.hrao.rid.config.RequestInterceptor());
logger.info("RequestInterceptor added to InterceptorRegistry");
}
}
JSONConfiguration.java is a controller I set up just for JSON.
package com.mytest.config;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
#Configuration
#ComponentScan(basePackages = {"com.mytest.controller"})
#EnableWebMvc
public class JSONConfiguration {
private Logger logger = LoggerFactory.getLogger(JSONConfiguration.class);
#Bean // needed for JSON conversion of bean responses
public View jsonTemplate() {
logger.info("Registered MappingJackson2JsonView");
MappingJackson2JsonView view = new MappingJackson2JsonView();
Properties props = new Properties();
props.put("order", 1);
view.setAttributes(props);
view.setPrettyPrint(true);
return view;
}
#Bean
public ViewResolver viewResolver() {
logger.info("Starting ViewResolver bean");
return new BeanNameViewResolver();
}
}
Implementation
In my Controller, the following method should return JSON.
#Autowired
AppConstants appConstants;
#RequestMapping(method = RequestMethod.GET, value = "getAppConstants")
public String getAppConstants(Model model) {
model.addAttribute("AppConstants",appConstants);
if(appConstants==null) {
Logger.error("appConstants not autowired!!!");
return null;
}
return "jsonTemplate";
}
As mentioned above in Things Tried, this works fine if I remove the ViewResolverRegistry bean from the SpringWebConfig and if I leave the bean in place, the above controller method returns
404, /WEB-INF/views/html/jsonTemplate.jsp
The requested resource is not available.
-- which I understand. That's what the view resolver should do. How do I make my JSON calls bypass this?
It turns out there were only a couple of things missing. The first was to add the following annotation to the bean declaration for the mapper:
#Primary
So now, the bean setup looks like this.
#Bean // needed for JSON conversion of bean responses
#Primary
public View jsonTemplate() {
logger.info("Registered MappingJackson2JsonView");
MappingJackson2JsonView view = new MappingJackson2JsonView();
Properties props = new Properties();
props.put("order", 1);
view.setAttributes(props);
view.setPrettyPrint(true);
return view;
}
The second was to use a ContentNegotiationConfigurer. In my SpringWebConfig, I added the following:
public void configurationContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.ignoreUnknownPathExtensions(false)
.defaultContentType(MediaType.TEXT_HTML);
}
and changed my configureViewResolvers function as follows:
#Override // needed for jsp resolving
public void configureViewResolvers(final ViewResolverRegistry registry) {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
registry.enableContentNegotiation(view);
registry.jsp("/WEB-INF/views/html/",".jsp");
}
One clue was found in this example. The rest came from the Spring documentation.

Can not read properties file value in Spring Configuration class

I am trying to simple spring program that has a class named PersistenceConfig annotated with #Configuration
#Configuration
#PropertySource("classpath:application.properties")
public class PersistanceConfig {
#Value("${dbPassword}")
private String dbPassword;
// Set of Beans and Code
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
dataSource.setUrl("jdbc:sqlserver://localhost;databaseName=GovernmentPayment;integratedSecurity=false;");
dataSource.setUsername("sa");
dataSource.setPassword(dbPassword);
return dataSource;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
When i run my program, the value dbPassword is always null but if i try to read the same value inside one my Controllers it reads the value without any issues.
I have tried autowiring Environment variable and using it instead of #Value but it didn't work either. (Spring didn't inject value to the Environment Variable)
I am using Spring 4
What is basically want is to externalize the database username and password in a separate property file.
i don't see any problem with given code.i wrote a simple unit test to your class to prove it works.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=PersistanceConfig.class)
public class PersistanceConfigTest {
#Autowired
private DriverManagerDataSource dataSource;
private final String password = "mydbPassword";
#Test
public void testDriverManagerDataSourcePassword() {
System.out.println("dataSource Password :: " + dataSource.getPassword());
assertNotNull(dataSource);
assertTrue(password.equals(dataSource.getPassword()));
}
}
assuming you have application.properties in src/main/resources and dbPassword=mydbPassword is presented in that file.
Credit goes to Chad Darby
This is an issue with Spring versions.
If you are using Spring 4.2 and lower, you will need to add the code in marked with(**).
package com.luv2code.springdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#Configuration
// #ComponentScan("com.luv2code.springdemo")
#PropertySource("classpath:sport.properties")
public class SportConfig {
// add support to resolve ${...} properties
**#Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}**
// define bean for our sad fortune service
#Bean
public FortuneService sadFortuneService() {
return new SadFortuneService();
}
// define bean for our swim coach AND inject dependency
#Bean
public Coach swimCoach() {
SwimCoach mySwimCoach = new SwimCoach(sadFortuneService());
return mySwimCoach;
}
}
````
In Spring 4.3 and higher, they removed this requirement. As a result, you don't need this code.
I have solved this by moving that two annotations to the main file.
package com.luv2code.springdemo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "com.luv2code.springdemo.SportConfig")
public class SwimJavaConfigDemoApp {
public static void main(String[] args) {
// read spring config java class
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SportConfig.class);
// get the bean from spring container
Coach theCoach = context.getBean("swimCoach", Coach.class);
// call a method on the bean
System.out.println(theCoach.getDailyWorkout());
// call method to get the daily fortune
System.out.println(theCoach.getDailyFortune());
// close the context
context.close();
}
}
Configure the main file.
Use component scan and specified the path to the cofig class.
Next, write some Bean's to the config file.
package com.luv2code.springdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
public class SportConfig {
// define a bean for sad fortune service
#Bean
public FortuneService sadFortuneService() {
return new SadFortuneService();
}
// define bean for our swim coach and inject dependency
#Bean
public Coach swimCoach() {
return new SwimCoach(sadFortuneService());
}
}
For futher learning : Component Scan.

Categories

Resources