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);
}
}
Related
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);
}
}
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;
Hi i'm new to spring boot and trying implement the security to my rest apis.
i'm using spring boot 2.0.7.release
i have configures my WebSecurityConfig as following
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Resource(name = "userService")
private UserDetailsService userDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(encoder());
}
#Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationFilter();
}
#Bean
public PasswordEncoder encoder(){
PasswordEncoder encoder = new CustomPasswordEncoder();
return encoder;
}
....
}
I have add the resource name so that i can point the to custom userDetailsService.
I have tried configuring authenticationManager Bean by came and pointing the bean by Qualifier authenticationManager bean still it the error remains same.
my pom.xml looks like for security
......
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
......
and my implemented UserServiceImpl is
#Service(value = "userService")
public class UserServiceImpl implements UserService, UserDetailsService {
#Autowired
private UserDAOService userDao;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByUsername(username);
if(user == null){
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), getAuthority());
}
#Override
public String login(LoginUser user) {
// valid user if it exits then do the following
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
//generate the token and do other process.
}
following are the error logs. i have provided only mail errors
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webSecurityConfig': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'authenticationManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authenticationManager' defined in class path resource [com/saikrishna/security/config/WebSecurityConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Circular reference involving containing bean 'webSecurityConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'authenticationManagerBean' threw exception; nested exception is java.lang.IllegalArgumentException: delegateBuilder cannot be null
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'authenticationManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authenticationManager' defined in class path resource [com/saikrishna/security/config/WebSecurityConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Circular reference involving containing bean 'webSecurityConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'authenticationManagerBean' threw exception; nested exception is java.lang.IllegalArgumentException: delegateBuilder cannot be null
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authenticationManager' defined in class path resource [com/saikrishna/security/config/WebSecurityConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Circular reference involving containing bean 'webSecurityConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'authenticationManagerBean' threw exception; nested exception is java.lang.IllegalArgumentException: delegateBuilder cannot be null
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Circular reference involving containing bean 'webSecurityConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'authenticationManagerBean' threw exception; nested exception is java.lang.IllegalArgumentException: delegateBuilder cannot be null
Caused by: java.lang.IllegalArgumentException: delegateBuilder cannot be null
at org.springframework.util.Assert.notNull(Assert.java:193) ~[spring-core-5.0.11.RELEASE.jar:5.0.11.RELEASE]
In order to help you better, it is better if you indicate which reference you are following to implement JWT mechansim.
Conceptually, this part of the source code is wrong:
#Override
public String login(LoginUser user) {
// valid user if it exits then do the following
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
//generate the token and do other process.
}
See if the modifications below can help you
1) Consider using Java Config to declare your beans, in a seperate Configuration class
#Configuration
public class ServiceConfig{
#Bean
protected UserDAOService daoService()
{
return new UserDAOServiceImpl();
}
#Bean
protected UserDetailsService userDetailService( UserDAOService dao )
{
return new UserServiceImpl( dao );
}
#Bean
public PasswordEncoder encoder(){
PasswordEncoder encoder = new CustomPasswordEncoder();
return encoder;
}
#Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception{ {
return new JwtAuthenticationFilter();
}
}
2) Modification to your WebSecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
protected void configure( AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService( userDetailsService ).passwordEncoder( passwordEncoder );
}
}
I have my Configuration Class with some Dependent Beans
public class WebConfig{
#Bean
#Qualifier("geojedis")
public StringRedisTemplate geoJedisTemplate(
#Qualifier("geographyJedisConnectionFactory") final JedisConnectionFactory connectionFactory) {
// Create a RedisTemplate implementation which is basically of string
// data structure.
StringRedisTemplate redisTemplate = new StringRedisTemplate(connectionFactory);
return redisTemplate;
}
#Bean
#Qualifier("capacityStringRedisTemplate")
public StringRedisTemplate capacityStringRedisTemplate(
#Qualifier("capacityJedisConnectionFactory") final JedisConnectionFactory connectionFactory) {
// Create a RedisTemplate implementation which is basically of string
// data structure.
StringRedisTemplate redisTemplate = new StringRedisTemplate(connectionFactory);
return redisTemplate;
}
#Bean
public JedisConnectionFactory geographyJedisConnectionFactory() {
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
return connectionFactory;
}
#Bean
public JedisConnectionFactory capacityJedisConnectionFactory() {
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
return connectionFactory;
}
}
But I am getting the below error. When i checked the configurations all are fine and I have also defined the Qualifier for mapping the correct dependencies. Any help is much appreciated.
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'redisTemplate' defined in class path
resource
[org/springframework/boot/autoconfigure/redis/RedisAutoConfiguration$RedisConfiguration.class]:
Unsatisfied dependency expressed through constructor argument with
index 0 of type
[org.springframework.data.redis.connection.RedisConnectionFactory]: :
No qualifying bean of type
[org.springframework.data.redis.connection.RedisConnectionFactory] is
defined: expected single matching bean but found 2:
geographyJedisConnectionFactory,capacityJedisConnectionFactory; nested
exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type
[org.springframework.data.redis.connection.RedisConnectionFactory] is
defined: expected single matching bean but found 2:
geographyJedisConnectionFactory,capacityJedisConnectionFactory
There is a bean inside RedisAutoConfiguration that is created if there is no default "redisTemplate" in Spring Context.
#Bean
#ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
This one needs a single RedisConnectionFactory, but finds two.
As a work-around you can create a dummy RedisTemplate with the name "redisTemplate" and not use it.
Since it checks by bean name, the following could be enough as long as nothing tries to #Autowire it:
#Bean
public Object redisTemplate() {
return new Object();
}
You can simply call the connection factory bean creation method instead of injection:
#Bean
public StringRedisTemplate capacityStringRedisTemplate() {
// Create a RedisTemplate implementation which is basically of string
// data structure.
StringRedisTemplate redisTemplate =
new StringRedisTemplate(capacityJedisConnectionFactory());
return redisTemplate;
}
This will point directly to the one your looking for
use #EnableAutoConfiguration(exclude = RedisAutoConfiguration.class) above your config class and provide the custom connection properties
I have a Spring service which is checking database entries. To minimize my repository calls both find methods are "#Cacheable". But when I try to init my service bean while my configuration class has a CacheManager bean definition I get following NoSuchBeanDefinitionException:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'foo.mediacode.directory.MediaCodeDirectoryService' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at foo.mediacode.directory.MediaCodeDirectoryService.implementation(MediaCodeDirectoryService.java:63)
at foo.campaigntree.directory.CampaignTreeDirectoryService.<init>(CampaignTreeDirectoryService.java:18)
... 15 more
If I take out the CacheManager bean definition, I can init my service bean and it runs without any problems and caching!
Here is my code:
Configuration
...
#Configuration
#EnableCaching
#EnableJpaRepositories(...)
#PropertySource({...})
public class MediaCodeDirectoryServiceConfig {
private static Logger configLogger = Logger.getLogger(MediaCodeDirectoryServiceConfig.class.getName());
#Value("${jpa.loggingLevel:FINE}")
private String loggingLevel;
#Value("${mysql.databaseDriver}")
private String dataBaseDriver;
#Value("${mysql.username}")
private String username;
#Value("${mysql.password}")
private String password;
#Value("${mysql.databaseUrl}")
private String databaseUrl;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
...
}
#Bean
public MediaCodeDirectoryService mediaCodeDirectoryService() {
return new MediaCodeDirectoryService();
}
#Bean
public CacheManager mediaCodeCacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("mediaCodeMappingRegexCache"),
new ConcurrentMapCache("mediaCodeMappingsCache")));
return cacheManager;
}
#Bean
public JpaTransactionManager transactionManager() {
...
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
...
}
public DataSource getDataSource() {
...
}
public JpaDialect getJpaDialect() {
...
}
public Properties getEclipseLinkProperty() {
...
}
public JpaVendorAdapter getJpaVendorAdapter() {
...
}
}
Service
....
public class MediaCodeDirectoryService implements MediaCodeDirectoryServiceApi {
...
#Autowired
private MediaCodeDirectoryRepository repo;
#SuppressWarnings("resource")
public static MediaCodeDirectoryServiceApi implementation() {
if (INSTANCE == null) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MediaCodeDirectoryServiceConfig.class);
INSTANCE = ctx.getBean(MediaCodeDirectoryService.class);
}
return INSTANCE;
}
...
Repository
...
#Repository
public interface MediaCodeDirectoryRepository extends CrudRepository<MediaCodeDao, Integer> {
#Cacheable("mediaCodeMappingRegexes")
#Query("SELECT m FROM #{#entityName} m WHERE (m.fooId = :fooId) AND (m.isRegex = :isRegex) ORDER BY (m.orderId DESC, m.id ASC)")
List<MediaCodeDao> findByfooIdAndIsRegexOrderByOrderIdDescAndIdAsc(#Param("fooId") int fooId, #Param("isRegex") boolean isRegex);
#Cacheable("mediaCodeMappings")
List<MediaCodeDao> findByMediaCode(String MediaCode, Pageable pageable);
}
When I debug into DefaultListableBeanFactory I can find within beanDefinitionMap my mediaCodeDirectoryService and also within beanDefinitionNames mediaCodeDirectoryService appears. But DefaultListableBeanFactory.getBean(...) cannot resolve name and namedBean in line 364 is null.
When I try to get the context via String like:
INSTANCE = (MediaCodeDirectoryService) ctx.getBean("mediaCodeDirecotryService")
I avoid the NoSuchBeanDefinitionException but I run into an other one.
Anybody here has an idea on what might be the cause of this? Did I missed something in my configuration? Thx!
Caching is applied through AOP. For AOP Spring uses a proxy based approach and the default is to create interface based proxies.
public class MediaCodeDirectoryService implements MediaCodeDirectoryServiceApi {... }
With this class definition at runtime you will get a dynamically created class (Proxy$51 or something along those lines) which implements all interfaces but it isn't a MediaCodeDirectoryService. It is however a MediaCodeDirectoryServiceApi.
You have 2 ways of fixing this, either program to interfaces (which you should have been doing anyway because you have defined interfaces) instead of concrete classes or use class based proxies.
The first option involves you changing your code in the places the directly #Autowire or get an instance of MediaCodeDirectoryService to use MediaCodeDirectoryServiceApi instead (which imho you should already do, why else define an interface). Now you will get the proxy injected and everything will work.
The second option involves you setting proxyTargetClass=true on your #EnableCaching annotation. Then instead of an interface based proxy you will get a class based proxy.
#EnableCaching(proxyTargetClass=true)