I am facing a weird issue in my application which runs on Spring Boot 1.4.0M3 which is using Spring cache implementation where provider is Redis where I receive classCastException that same object cannot be casted
I am using Mongodb as database and I have User Object which contains List of Roles object loaded lazily and Roles internally contains Permissions Object like below
#Document
#Data
public class User implements Serializable{
private String passwordResetToken;
private boolean enabled = false;
#DBRef(lazy= true)
private List<Role> roleList;
}
My Role DTO is as below
#Data
#Document
public class Role implements Serializable{
private String roleName;
private String description;
#DBRef(lazy= true)
private List<Permission> permissions;
}
Now in my spring MVC while loading all roles I am calling all permissions and since this is repetitive operation I thought of caching the result and using redis and while loading the roles value I receive below exception.
raised java.lang.ClassCastException: com.learning.securedapp.domain.Permission cannot be cast to com.learning.securedapp.domain.Permission
Help me to overcome this error.
I am attaching the source code to my project and I receive error at line 91 of RoleController.java
To Replicate in your local environment login to application and click on permissions menu and then roles menu, In Roles menu now click on any edit icon.you will receive above error.
When you use DevTools with caching, you need to be aware of this limitation.
When the object is serialized into the cache, the application class loader is C1. Then after you change some code/configuration, devtools automatically restart the context and creates a new classloader (C2). When you hit that cache method, the cache abstraction finds an entry in the cache and it deserializes it from the store. If the cache library doesn't take the context classloader into account, that object will have the wrong classloader attached to it (which explains that weird exception A cannot be cast to A).
TL;DR do not serialize classes with devtools if the cache library doesn't use the context classloader. Or put your cache library in the application classloader:
restart.include.yourcache=/my-cache-lib-[\\w-]+\.jar
This worked for me , DevTools and Redis both are working. We need to pass classLoader when creating JdkSerializationRedisSerializer and it should work
JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());
So my RedisCacheConfig is:
#Configuration
#EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport implements CachingConfigurer {
............................
............................
#Bean
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofHours(redisDataTTL))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));
redisCacheConfiguration.usePrefix();
RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
redisCacheManager.setTransactionAware(true);
return redisCacheManager;
}
............................
............................
}
Check this spring boot issue: https://github.com/spring-projects/spring-boot/issues/9444
I actually tried the proposed solution (and many variations thereof) with no luck. E.g., this didn't stop the problem from occurring:
restart.include.cache=/spring-data-redis-.*.jar
I updated the above to callout the specific version I was using and it still didn't work.
What I ended up doing which did work was to exclude spring-boot-devtools from my project. I'm using Maven so the annotation was this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>[1.5.9,)</version>
<scope>provided</scope>
</dependency>
This will prevent any version equal to or greater than 1.5.9 from loading up. After I included the above, everything worked as expected. I know this isn't an ideal solution for all, but I made little use of the restart functions of devtools so this was actually a good approach for me.
I am using Spring Boot 2.0.5, and I ended up removing devtools altogether from pom.xml. Thanks to the answer above from #Always Learning.
As much as I hate to do this, but I can't find another way for now!
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
-->
Related
I want to cache the following getMessagesList method. I want to call one time When user log into the system. Therefor I think caching is the best solution for that. And I need to remove when user log out. How I can do this.
public List<String> getMessagesList(String username)
{ // return messages list in DB by username}
My project was create using Maven 4.0 and Spring MVC. spring version 5.3
Assuming you use Spring Security as part of your app, it should be managing your session, and every time you log out, it will create a new session. Unless you had posted this code, I'm not going to be able to help you there. However, assuming you can log in/out, this should be covered already.
As for the cacheing, in general, this sounds like a Database Caching need, which is something that you would use Spring Boot Caching on.
To use this in Spring Boot, you would add the following dependency to maven (or the equivalent in Gradle, etc):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Adjust your application to allow using Cacheing, which can be done by adding the annotation #EnableCaching to your Spring Boot application
#SpringBootApplication
#EnableCaching
public class MyApplication {
...
}
Create a Java Service Object, called something like MessagesService.class:
#CacheConfig(cacheNames={"Messages"})
public class MessagesService {
#Cacheable(value="cacheMessages")
List<String> getMessages() {
//access the database to load data here
...
}
...
}
I am developing a module with spring boot in my backend where i need to use Redis through GCP Memory Store. I have been searching in forum and even the "oficial documentation" about memory store but i cannot understand how to connect to memory store with my spring boot app.
I found a google code lab but they use a Compute Engine VM to install spring boot and then save and retrieve information from memory store. So i tried to do it like that in my local spring boot but it didnt work because throws an error saying:
Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.1.3.4
the codelab i mentioned earlier says that you only have to add this line to your application.properties:
spring.redis.host=10.1.3.4
as well as the annotation #EnableCaching in the main class and #Cachable annotation in the controller method where you try to do something with redis.
the method looks like this:
#RequestMapping("/hello/{name}")
#Cacheable("hello")
public String hello(#PathVariable String name) throws InterruptedException {
Thread.sleep(5000);
return "Hello " + name;
}
i dont know what else to do. Notice that i am new on this topic of redis and memory store.
Anyone can give me some guidance on this please?
thanks in advance
codelab url: https://codelabs.developers.google.com/codelabs/cloud-spring-cache-memorystore#0
See this documentation on how to setup Memorystore Redis instance.
Included in the documentation is how you can connect and test your Memorystore instance from different computing environments.
There's also a step by step guide on how SpringBoot can use Redis to cache with annonations.
Add the Spring Data Redis starter in your pom.xml if you're using Maven for your project setup.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Add this configuration in your application.properties file:
spring.redis.host=<MEMORYSTORE_REDIS_IP>
# Configure default TTL, e.g., 10 minutes
spring.cache.redis.time-to-live=600000
Turn on caching capability explicitly with the #EnableCaching annotation:
#SpringBootApplication
#EnableCaching
class DemoApplication {
...
}
Once you configured the Spring Boot with Redis and enabled caching, you can use the #Cacheable annotation to cache return values.
#Service
class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
#Cacheable("order")
public Order getOrder(Long id) {
orderRepository.findById(id);
}
}
I'm starting a new project, and decided to try neo4j with springboot data neo4j and OGM. Everything is working just fine, but in my development env, the spring-boot-devtools is not helping much.
Every time that I change a java class, the Automatic restart triggers and then any query that I run throws a ClassCastException like
java.lang.ClassCastException: br.com.ncisaude.gr.dominio.usuario.Usuario cannot be cast to br.com.ncisaude.gr.dominio.usuario.Usuario
at com.sun.proxy.$Proxy133.findByEmail(Unknown Source)...
Obviously it is a classloader issue, because the classes are just the same.
I believe that neo4j OGM or spring-data-neo4j use serialization for caching or something like that and this is causing this Exception, but im not realy sure.
Someone knows a workarround for this? if it is cache related, there is any way to disable those cache?
I dont know if I should send an issue to neo4j ogm or spring-boot-neo4j, any insights on this?
I'm running spring boot version 1.5.3 with bolt driver 2.1.2. My configuration has nothing specific, its just the default springboot setup with neo4j.
#Configuration
#EnableSpringConfigured
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
#EnableScheduling
#EntityScan("br.com.ncisaude.gr.dominio")
public class SpringConfig {
#Bean
#Profile("dev")
public org.neo4j.ogm.config.Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
AutoIndexConfiguration autoIndexConfiguration = config.autoIndexConfiguration();
// Modo assert remove e cria todas as constraints
autoIndexConfiguration.setAutoIndex("assert");
DriverConfiguration driverConfiguration = config.driverConfiguration();
driverConfiguration.setURI("bolt://localhost");
driverConfiguration.setCredentials("neo4j", "******");
return config;
}
}
Thanks in Advance
[]s
Please see my reply to this issue here: https://github.com/neo4j/neo4j-ogm/issues/374
I am using spring boot, and I have two external properties files, so that I can easily change its value.
But I hope spring app will reload the changed value when it is updated, just like reading from files. Since property file is easy enough to meet my need, I hope I don' nessarily need a db or file.
I use two different ways to load property value, code sample will like:
#RestController
public class Prop1Controller{
#Value("${prop1}")
private String prop1;
#RequestMapping(value="/prop1",method = RequestMethod.GET)
public String getProp() {
return prop1;
}
}
#RestController
public class Prop2Controller{
#Autowired
private Environment env;
#RequestMapping(value="/prop2/{sysId}",method = RequestMethod.GET)
public String prop2(#PathVariable String sysId) {
return env.getProperty("prop2."+sysId);
}
}
I will boot my application with
-Dspring.config.location=conf/my.properties
I'm afraid you will need to restart Spring context.
I think the only way to achieve your need is to enable spring-cloud. There is a refresh endpoint /refresh which refreshes the context and beans.
I'm not quite sure if you need a spring-cloud-config-server (its a microservice and very easy to build) where your config is stored(Git or svn). Or if its also useable just by the application.properties file in the application.
Here you can find the doc to the refresh scope and spring cloud.
You should be able to use Spring Cloud for that
Add this as a dependency
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.2.RELEASE'
And then use #RefreshScope annotation
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
Also relevant if you have Spring Actuator
For a Spring Boot Actuator application there are some additional management endpoints:
POST to
/env to update the Environment and rebind #ConfigurationProperties and log levels
/refresh for re-loading the boot strap context and refreshing the #RefreshScope beans
Spring Cloud Doc
(1) Spring Cloud's RestartEndPoint
You may use the RestartEndPoint: Programatically restart Spring Boot application / Refresh Spring Context
RestartEndPoint is an Actuator EndPoint, bundled with spring-cloud-context.
However, RestartEndPoint will not monitor for file changes, you'll have to handle that yourself.
(2) devtools
I don't know if this is for a production application or not. You may hack devtools a little to do what you want.
Take a look at this other answer I wrote for another question: Force enable spring-boot DevTools when running Jar
Devtools monitors for file changes:
Applications that use spring-boot-devtools will automatically restart
whenever files on the classpath change.
Technically, devtools is built to only work within an IDE. With the hack, it also works when launched from a jar. However, I may not do that for a real production application, you decide if it fits your needs.
I know this is a old thread, but it will help someone in future.
You can use a scheduler to periodically refresh properties.
//MyApplication.java
#EnableScheduling
//application.properties
management.endpoint.refresh.enabled = true
//ContextRefreshConfig.java
#Autowired
private RefreshEndpoint refreshEndpoint;
#Scheduled(fixedDelay = 60000, initialDelay = 10000)
public Collection<String> refreshContext() {
final Collection<String> properties = refreshEndpoint.refresh();
LOGGER.log(Level.INFO, "Refreshed Properties {0}", properties);
return properties;
}
//add spring-cloud-starter to the pom file.
Attribues annotated with #Value is refreshed if the bean is annotated with #RefreshScope.
Configurations annotated with #ConfigurationProperties is refreshed without #RefreshScope.
Hope this will help.
You can follow the ContextRefresher.refresh() code implements.
public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}
I am trying out the ResourceProcessor interface in Spring Data REST. I don't think my Processor ever gets called. No error message either.
Here is my processor (in Groovy):
#Autowired
PersonService personService
#Override
public Resource<Person> process(Resource<Person> resource) {
resource.content.isAdult = personService.isAdult(resource.content)
// sanity check: does this link get added?? (NOPE!!)
resource.add(new Link("http://localhost:8080/people", "added-link"))
log.info "## resource.content.isAdult ==> ${resource.content}"
return resource
}
Any help would be most appreciated!! You can see the entire project here in GitHub: https://github.com/txiasummer/spring-data-rest-examples
Finally got it to work! It turns out to be something completely trivial and I can't believe I missed it. I have a PersonProcessor classes which implements Spring's native ResourceProcessor interface. But PersonProcessor is still just a basic class that must be injected by Spring!! I think I was getting it confused with #Projection, which will be recognized automatically and does not need to be injected explicitly.
I addd #ComponentScan to my Application.groovy and now everything is working swimmingly. Alternatively, you an also manually define the PersonProcessor class and its service PersonService class as #Bean in Application.groovy. Again, you can see the whole project here: https://github.com/txiasummer/spring-data-rest-examples