Neo4j-OGM triggers ClassCastException on any query after spring-boot-devtools restart - spring-boot

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

Related

I am not able to connect to Google Cloud Memory Store from Spring Boot

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);
}
}

How to configure DispatcherType's for SecurityFilterAutoConfiguration?

I have a Spring Boot (2.1.5) application which uses the SecurityFilterAutoConfiguration feature. During registration of DelegatingFilterProxyRegistrationBean only REQUEST, ASYNC, ERROR DispatcherTypes are set. But I need FORWARD and INCLUDE as well.
The property security.filter-dispatcher-types from Spring Boot 1.x no longer works.
I can work around the problem by "overwriting" the DelegatingFilterProxyRegistrationBean as follows:
#Bean
#ConditionalOnBean(name = DEFAULT_FILTER_NAME)
#Primary
public DelegatingFilterProxyRegistrationBean customSecurityFilterChainRegistration(SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(allOf(DispatcherType.class));
return registration;
}
But that doesn't seem like a very elegant solution to me.
Is there a way to configure this for Spring Boot 2.1.x explicit?
You have to use spring.security.filter.dispatcher-types, see Spring Boot 2.0 Configuration Changelog.

How to configure Spring Boot with elasticsearch 5.2.1?

I am trying to connect my Spring Boot application to local elasticsearch 5.2.1 instance. When i use "org.springframework.boot:spring-boot-starter-data-elasticsearch" dependency, i face with "Received message from unsupported version: [2.0.0] minimal compatible version is: [5.0.0]". I think this is due to elasticsearch version is 2.4.4 in starter dependency. So to solve this error, i edit pom.xml properties by adding elasticsearch.version>5.2.1/elasticsearch.version> line. But this time i get
"java.lang.NoSuchMethodError: org.elasticsearch.client.transport.TransportClient.builder()"
To overcome this issue, i create custom config class like below:
#Configuration
public class ElasticsearchConfiguration {
#Bean
public Client client() throws UnknownHostException {
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
return client;
}
#Bean
public ElasticsearchTemplate elasticsearchTemplate() throws UnknownHostException {
return new ElasticsearchTemplate(client());
}
}
This time i get apache.logging.log4j exceptions (check here) so i add necessary dependencies.
Finally i get below error and stucked there. Could anyone help me out with this?
nested exception is java.lang.NoClassDefFoundError:org/elasticsearch/action/count/CountRequestBuilder
The github page of spring-data-elasticsearch shows that it currently supports elasticsearch only up to version 2.4.0.
For now you have 3 options:
Wait and hope
checkout the pull request
checkout the dev branch 5.0.x-prep
You need to use Spring Boot 2. Check out my spring-boot-elasticsearch-5.x example.
You can use elasticsearch java api to create transport client instead of using spring-data-elasticsearch.
I tried the same and getting that error too for CountRequestBuilder, reason is that CountRequestBuilder class is deprecated and removed now from 5.x elastic search versions, that class is replaced by SearchRequestBuilder but unfortunately spring-data-elasticsearch don't provide this even in the latest release of its jar and that CountRequestBuilder is used in ElasticSearchTemplate.
I am also looking out for some solution. I will post if able to resolve.

Reload property value when external property file changes ,spring boot

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;
}

Setting Flyway 'baselineOnMigrate' and 'baselineVersion' using spring boot property file

Spring Boot's FlywayProperties.java supports many of the Flyway settings but not 'baselineVersion' or 'baselineOnMigrate'. I am converting an existing application to Flyway and these setting appear to be designed for this purpose. Our production environment is highly controlled and running a commandline version of flyway there to achieve this is not practical.
Is creating a custom Flyway #Bean the only option here?
You can set any of flyways properties be prefixing them with flyway in your application.yml/.properties.
It is made possible by org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayConfiguration#flyway which is annotated with #ConfigurationProperties(prefix = "flyway").
If you are using an application.yml add the following:
spring:
flyway:
baselineOnMigrate: true
If using an application.properties add the following:
spring.flyway.baselineOnMigrate = true
Update: added prefix spring (see #pdem comment).
It is impossible. I spent some time today analyzing code of Spring Boot to try to find a solution to this. There is nothing about setting any of these properties in FlywayAutoConfiguration. Also I found that Spring is never calling configure method on Flyway object what would be the only other option for flyway.properties to work. Spring is abusing flyway.properties a little bit and instead of providing this file further to Flyway they use it themselves as a source of properties. That is why the set of possible options when using FlywayAutoConfiguration is so limited. So using FlywayAutoConfiguration is not a good option if you need any more advanced features of Flyway. But using #Bean is not a tragedy here. Below you may see an example of using #Bean this way that implementing this behavior would be impossible with any property files:
#Profile(value = "!dbClean")
#Bean(name = "flyway", initMethod = "migrate")
public Flyway flywayNotADestroyer() {
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource());
flyway.setBaselineOnMigrate(true);
return flyway;
}
#Profile(value = "dbClean")
#Bean(name = "flyway", initMethod = "migrate")
public Flyway flywayTheDestroyer() {
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource());
flyway.setBaselineOnMigrate(true);
flyway.clean();
return flyway;
}
As you can see I have two Spring profiles here. One default that will not clean your database, and one with full clean of the database. Very handy.
I had success using a FlywayMigrationStrategy.
#Component
public class BaselineOnMigrateMigrationStrategy implements FlywayMigrationStrategy {
#Override
public void migrate(Flyway flyway) {
flyway.setBaselineOnMigrate(true);
flyway.migrate();
}
}
You can to use on application.properties file, but you need to add spring. prefix to it for springboot 2 like #pdem marked in this answer comments https://stackoverflow.com/a/39244097/273119.
spring.flyway.baseline-on-migrate=true
I am using flyway 5.1.4, for me adding these in application.properties worked
flyway.enabled = true
flyway.baseline-on-migrate = true
After digging into the source and running some experiments, it would appear that because the setBaselineVersion() is overloaded in the Flyway class, Spring is unable to inject the property value.
Changing to flyway.baselineVersionAsString=2 works as desired.
Answer of Seth is worked for me.
But I changed
flyway.setBaselineOnMigrate(true);
for
flyway.baseline();

Resources