How can I inject the following application.properties into a Map field?
my.server.url=localhost
my.server.port=8080
my.server.timeout=10000
What is wrong with the following class?
#Service
#ConfigurationProperties("my")
public class MyService {
private Map<String, String> server;
public void setServer(Map<String, String> server) { this.server = server; }
public MyService(WebClient.Builder builder) {
this.builder = builder.uri(server.get("url")).build();
}
}
Result:
Bean instantiation via constructor failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [MyService]: Constructor threw exception; nested exception
is java.lang.NullPointerException
create a bean as following in the configuration class :
#Bean(name = "appProperties")
public static PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("application.properties"));
return bean;
}
And then inject the values in it as map as follows in to the desired class :
#Resource(name = "appProperties")
private Map<String, String> properties;
Related
I am desperately attempting to populate the Environment with properties necessary to resolve bean properties in one of the scanned in components. What follows is a simple demonstration of two failed attempts to populate the environment.
This is the class whose bean property fails to get resolved during construction of the application context.
package com.enterprise.samples.email;
import ...
#Component
public class EmailBean {
#Value("mail.retry.count")
private int retryCount;
public int getRetryCount() {
return retryCount;
}
}
This is the java configuration class.
package com.enterprise.samples.configuration;
import ...
#Configuration
#PropertySource(value="classpath:aux.properties")
#ComponentScan(basePackages={ "com.enterprise.samples.email" })
public class Conf {
#Autowired
private ConfigurableEnvironment env;
// failed attempt #1
#PostConstruct
public void after() {
final MutablePropertySources mutablePropertySources = env.getPropertySources();
final HashMap<String, Object> emailProperties = new HashMap<>();
emailProperties.put("mail.retry.count", 3);
final MapPropertySource emailPropertiesSource =
new MapPropertySource("emailProperties", emailProperties);
mutablePropertySources.addFirst(emailPropertiesSource);
}
// failed attempt #2
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
final HashMap<String, Object> emailProperties = new HashMap<>();
emailProperties.put("mail.retry.count", 3);
final MapPropertySource emailPropertiesSource =
new MapPropertySource("emailProperties", emailProperties);
final MutablePropertySources mutablePropertySources = new MutablePropertySources();
mutablePropertySources.addFirst(emailPropertiesSource);
final PropertySourcesPlaceholderConfigurer result = new PropertySourcesPlaceholderConfigurer();
result.setPropertySources(mutablePropertySources);
return result;
}
}
Finally, this is the test class.
package com.enterprise.samples.tests;
import ...
public class BeanPropertyResolutionTest {
#Test
public void test() {
final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Conf.class);
try {
final EmailBean emailBean = applicationContext.getBean(EmailBean.class, "emailBean");
Assert.assertEquals(3, emailBean.getRetryCount());
} finally {
applicationContext.close();
}
}
}
The following exception results:
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'emailBean': Unsatisfied dependency expressed through field 'retryCount'; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "mail.retry.count"
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'emailBean': Unsatisfied dependency expressed through field 'retryCount'; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "mail.retry.count"
Can anyone tell me what I am doing incorrectly?
I assume your problem is here: #Value("mail.retry.count"). You almost got it right. You should've written this #Value("${mail.retry.count}"). And you don't need those attempt#1 and attempt#2.
I'm trying to caching jpa entity to redis through #Cacheable annotation.
[RedisConfig.class]
#Configuration
public class RedisConfig {
#Value("${spring.redis.host}")
private String host;
#Value("${spring.redis.port}")
private int port;
#Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
#Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
[Service layer]
#Service
#RequiredArgsConstructor
#Transactional(readOnly = true)
public class RoomQueryService {
private final RoomRepository roomRepository;
#Cacheable(value = "search", key = "#code")
public Room searchRoomByCode(String code) {
return roomRepository.findByCode(code).orElseThrow(RoomNotFoundException::new);
}
}
When executed above code, it throw below error.
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [slido.slidoclone.room.domain.Room]] with root cause
Maybe it caused because DefaultSerializer can't serialize jpa entity class.
So I added below 2 lines to RedisConfig.
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
But it throw same error.
After searching about it, I found 2 solutions.
Add implements Serializable to JPA entity
Use cacheManager in #Cacheable annotation
I'm curious as to which method is used in production.
Thanks.
I think your RedisTemplate isn't actually used anywhere. You'd have to supply a RedisCacheConfiguration instead (taken from "Spring Boot Cache with Redis"):
#Bean
public RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(60))
.disableCachingNullValues()
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
Add annotation #EnableCaching and see the effect.
#Service
#RequiredArgsConstructor
#Transactional(readOnly = true)
#EnableCaching
public class RoomQueryService {
private final RoomRepository roomRepository;
#Cacheable(value = "search", key = "#code")
public Room searchRoomByCode(String code) {
return
roomRepository.findByCode(code).orElseThrow(RoomNotFoundException::new);
}
}
I am trying to implement remember function for my Spring Security Application. And I used Redis also. I configured, SpringSessionBackedSessionRegistry beans. But when I try to #Autowired FindByIndexNameSessionRepository I got the following error,
Caused by: java.lang.IllegalArgumentException: sessionRepository
cannot be null
The code is as follows,
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private FindByIndexNameSessionRepository<? extends Session> sessionRepository;
#Bean
public SpringSessionBackedSessionRegistry sessionRegistry() {
return new SpringSessionBackedSessionRegistry(this.sessionRepository);
}
}
Handler.java
#Component
public class Handler {
private #Autowired SessionRegistry sessionRegistry;
private #Autowired FindByIndexNameSessionRepository<? extends Session> sessionRepository;
}
And Redis Session Configuration,
#Configuration
#EnableSpringHttpSession
public class SessionConfig {
private final RedisConnectionFactory redisConnectionFactory;
public SessionConfig(ObjectProvider<RedisConnectionFactory> redisConnectionFactory) {
this.redisConnectionFactory = redisConnectionFactory.getIfAvailable();
}
#Bean
public RedisOperations<String, Object> sessionRedisOperations() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(this.redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
#Bean
public RedisSessionRepository redisSessionRepository(RedisOperations<String, Object> sessionRedisOperations) {
return new RedisSessionRepository(sessionRedisOperations);
}
}
I get errors like,
Caused by: java.lang.IllegalArgumentException: sessionRepository
cannot be null Caused by:
org.springframework.beans.BeanInstantiationException: Failed to
instantiate
[org.springframework.session.security.SpringSessionBackedSessionRegistry]:
Circular reference involving containing bean 'securityConfig' -
consider declaring the factory method as static for independence from
its containing instance. Factory method 'sessionRegistry' threw
exception; nested exception is java.lang.IllegalArgumentException:
sessionRepository cannot be null Caused by:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'sessionRegistry' defined in class path
resource [SecurityConfig.class]: Bean instantiation via factory method
failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate
[org.springframework.session.security.SpringSessionBackedSessionRegistry]:
Circular reference involving containing bean 'securityConfig' -
consider declaring the factory method as static for independence from
its containing instance. Factory method 'sessionRegistry' threw
exception; nested exception is java.lang.IllegalArgumentException:
sessionRepository cannot be null
Also it says,
No beans of 'FindByIndexNameSessionRepository<? extends Session>' type
found.
So what I am doing wrong here?
Maybe, I am not sure, because this circular dependency error...
In any case, the problem probably is happening because you do not actually have a FindByIndexNameSessionRepository injected in your Spring context, at least not the one you are trying to configure, but a SessionRepository, because you are defining a bean of type RedisSessionRepository and this interface implements SessionRepository, not FindByIndexNameSessionRepository. Please, try to use a RedisIndexedSessionRepository instead, something like:
#Configuration
#EnableSpringHttpSession
public class SessionConfig {
private final RedisConnectionFactory redisConnectionFactory;
public SessionConfig(ObjectProvider<RedisConnectionFactory> redisConnectionFactory) {
this.redisConnectionFactory = redisConnectionFactory.getIfAvailable();
}
#Bean
public RedisOperations<String, Object> sessionRedisOperations() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(this.redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
#Bean
public FindByIndexNameSessionRepository redisSessionRepository(RedisOperations<String, Object> sessionRedisOperations) {
return new RedisIndexedSessionRepository(sessionRedisOperations);
}
}
I need use a bean inject with #Component #FeignClient(name = "xxx") when my spring boot application initializing, but it always throws exception like this:
20180706 10:18:40,043 WARN [main]
[org.springframework.context.annotation.AnnotationConfigApplicationContext]
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'feignContract' defined in org.springframework.cloud.netflix.feign.FeignClientsConfiguration: Unsatisfied dependency expressed through method 'feignContract' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'feignConversionService' defined in org.springframework.cloud.netflix.feign.FeignClientsConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.format.support.FormattingConversionService]: Factory method 'feignConversionService' threw exception; nested exception is java.lang.StackOverflowError
my feignClient code:
#Component
#FeignClient(name = "domain-account")
public interface IDomainService {
#RequestMapping(value = "/userInfos", method = RequestMethod.GET)
public String getUserInfos(#QueryMap Map<String, Object> condition);
}
ApplicationListenner code:
public class GlobalInit implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("======== GlobalInit ========");
IDomainService domainService = contextRefreshedEvent.getApplicationContext().getBean(IDomainService.class);
System.out.println("*********************" + domainService);
GlobalInitManager.getInstance().doInit();
}
}
It's not entirely clear for me what you try to do with the GlobalInit but the 'standard' way of designing your Feign client in Spring Boot would the following:
#SpringBootApplication
#EnableFeignClients
#EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
#EnableCaching
public class MyHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(MyHelloWorldApplication.class, args);
}
}
#Component
public class HelloWorldServiceImpl implements HelloWorldService {
#Autowired
private IDomainService iDomainService ;
public void myMethod() {
String userinfo = iDomainService.getUserInfos(...);
}
}
Hopefully this helps.
All the best,
Wim
Here is my class
#Configuration
class MongoDBConfig {
private Logger logger = LoggingFactory.getLogger(getClass());
#Bean
#Scope(value = "singleton", proxyMode = ScopedProxyMode.INTERFACES)
public MongoClient mongoClient() throws UnknownHostException {
logger.error("In Dev mode:");
return new MongoClient("fctest");
}
#Bean
public DB mongoDB() throws UnknownHostException{
try {
return mongoClient().getDB(FCProperties.MONGO_DB_NAME);
}catch (UnknownHostException ue){
logger.error("Error occurred: "+ue.getMessage());
throw ue;
}
}
}
And here is how I'm using it -
public class UserRepository extends BaseRepository {
#Autowired
public UserRepository(DB mongoDB) {
super("users", mongoDB);
}
}
I'm getting the following error
Error creating bean with name 'mongoDB' defined in class path resource [com/fctest/mongo/config/MongoDBConfig.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public com.mongodb.DB com.fctest.mongo.config.MongoDBConfig.mongoDB() throws java.net.UnknownHostException] threw exception; nested exception is java.lang.ClassCastException: com.sun.proxy.$Proxy13 cannot be cast to com.mongodb.MongoClient