Bootstrapping Spring Data Neo4j repositories - spring-boot

I am starting with Spring Data Neo4j, using Spring Boot 3.0.0.
Created application with Spring Initializr, added a Node and a Repository.
Neo4jDemo,java
#SpringBootApplication
public class Neo4jDemo {
public static void main(String[] args) {
SpringApplication.run(Neo4jDemo.class, args);
}
}
Player.java
#Node("Player")
#RequiredArgsConstructor
public class Player {
#Id
private final String name;
}
PlayerRepository.java
public interface PlayerRepository extends ReactiveNeo4jRepository<Player, String> {
}
When I run this, It shows Finished Spring Data repository scanning message twice, with different repository count.
[ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Neo4j repositories in DEFAULT mode.
[ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 123 ms. Found 1 Neo4j repository interfaces.
[ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Neo4j repositories in DEFAULT mode.
[ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 2 ms. Found 0 Neo4j repository interfaces.
Am I missing something ?
Or just ignore these messages ?
Thanks

After adding following to application.properties, it shows Finished Spring Data repository scanning message, only once (with correct repository count)
application.properties
.
.
.
spring.data.neo4j.repositories.type = reactive
I guess, earlier it was looking for both (reactive and imperative) type of repositories.

Related

Spring Boot 3 with Kotlin throws java.lang.UnsupportedOperationException for data class on GraalVM

Trying to run a very simple Spring Boot 3 app on GraalVM. The app just stores some data in H2 on startup. It is basically the same as what Josh does in the Spring Tips about Ahead-of-Time compilation, but using Kotlin instead of Java.
When starting the native image, I get the following error after Spring startup:
java.lang.UnsupportedOperationException: Kotlin class com.example.demo.basics.Customer has no .copy(…) method for property id
at org.springframework.data.mapping.model.BeanWrapper$KotlinCopyUtil.setProperty(BeanWrapper.java:171) ~[na:na]
at org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:79) ~[na:na]
...
I'm pretty new to GraalVM and Spring Native Images, don't know if I am missing something basic which needs to be configured when using Kotlin with Spring. The missing copy methods for the data class should have been generated by Kotlin, so I guess something is left out by the native compile related to Kotlin specifically.
The code which fails is the following class:
#Configuration
class BasicsConfiguration {
#Bean // execute on application start
fun basicsApplicationListener(customerRepository: CustomerRepository): ApplicationListener<ApplicationReadyEvent> {
return ApplicationListener<ApplicationReadyEvent> {
// store some values in the database
customerRepository
.saveAll(listOf("A", "B", "C").map { Customer(null, it) })
.forEach { println(it) }
}
}
}
interface CustomerRepository : CrudRepository<Customer, Int>
data class Customer(#Id val id: Long?, val name: String)
Running the app on the JDK works perfectly fine: ./gradlew bootRun
2022-11-30T11:23:15.300+01:00 INFO 33997 --- [ main] com.example.demo.DemoApplicationKt : Started DemoApplicationKt in 2.383 seconds (process running for 2.733)
Customer(id=1, name=A)
Customer(id=2, name=B)
Customer(id=3, name=C)
The native image is also created successfully: ./gradlew nativeCompile
Starting the native image works, the server process starts up but then fails:
2022-11-30T11:08:11.085+01:00 INFO 33059 --- [ main] com.example.demo.DemoApplicationKt : Started DemoApplicationKt in 0.147 seconds (process running for 0.158)
2022-11-30T11:08:11.089+01:00 ERROR 33059 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.UnsupportedOperationException: Kotlin class com.example.demo.basics.Customer has no .copy(…) method for property id
at org.springframework.data.mapping.model.BeanWrapper$KotlinCopyUtil.setProperty(BeanWrapper.java:171) ~[na:na]
at org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:79) ~[na:na]
...
Seems like this is an issue with Spring Data, which is not providing all necessary reflection hints for the native image creation. Specifically the reflection configuration for data classes' copy$default methods are missing. Will (probably) be fixed with Spring 6.0.3 release, see this issue for details: https://github.com/spring-projects/spring-framework/issues/29593
Workaround: add something like this in your reflect-config.json for the given data class:
{
"name": "copy$default",
"parameterTypes": [
"com.example.demo.basics.Customer",
"java.lang.Long",
"java.lang.String",
"int",
"java.lang.Object"
]
}

Spring boot 2 configure reactive mongo db repository WITHOUT EmbeddedMongo

I am trying to set up a Spring Boot 2 project with Mongo DB but I the problem I am facing is that it keeps spinning up an embedded mongo DB even though I have configured to use external mongo
logs
2018-11-27 18:56:05.725 INFO 73687 --- [ Thread-2] o.s.b.a.mongo.embedded.EmbeddedMongo : note: noprealloc may hurt performance in many applications
2018-11-27 18:56:05.742 INFO 73687 --- [ Thread-2] o.s.b.a.mongo.embedded.EmbeddedMongo : 2018-11-27T18:56:05.741+0200 I CONTROL [initandlisten] MongoDB starting : pid=73690 port=50303 dbpath=/var/folders/pf/qp_pv2xn7xb7ysnltp6tc97cstys_v/T/embedmongo-db-c2738896-198f-4934-87c4-3bd773508af7 64-bit host=MBP15-N5AXG8WP
2018-11-27 18:56:05.742 INFO 73687 --- [ Thread-2] o.s.b.a.mongo.embedded.EmbeddedMongo : 2018-11-27T18:56:05.741+0200 I CONTROL [initandlisten] db version v3.5.5
2018-11-27 18:56:05.742 INFO 73687 --- [ Thread-2] o.s.b.a.mongo.embedded.EmbeddedMongo : 2018-11-27T18:56:05.741+0200 I CONTROL [initandlisten] git version: 98515c812b6fa893613f063dae568ff8319cbfbd
2018-11-27 18:56:05.742 INFO 73687 --- [ Thread-2] o.s.b.a.mongo.embedded.EmbeddedMongo : 2018-11-27T18:56:05.741+0200 I CONTROL [initandlisten] allocator: system
Config
#EnableReactiveMongoRepositories
public class MongoReactiveApplication {
#Value("${spring.data.mongodb.uri}")
private String mongoUri;
#Bean
public MongoClient mongoClient() {
return MongoClients.create(mongoUri);
}
}
yaml
spring.data.mongodb.uri: mongodb://localhost:27017/mongotest
How should I change configuration to use external mongo?
Adding these beans helped me to connect to my external mongo
#Value("${spring.data.mongodb.uri}")
private String mongoUri;
#Bean
public MongoClient mongoClient() {
return MongoClients.create(mongoUri);
}
#Bean
public ReactiveMongoTemplate reactiveMongoTemplate() {
return new ReactiveMongoTemplate(reactiveMongoDatabaseFactory());
}
#Bean
public ReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory() {
return new SimpleReactiveMongoDatabaseFactory(mongoClient(), "mongotest");
}
Try this
spring:
data:
mongodb:
uri: mongodb://localhost:27017/mongotest

Spring Boot will not start when using Spring Integration and JdbcMetadataStore

I am trying to use Spring Integration to read files via SFTP and to use multiple servers to only read each file once. I have configured the SFTP reader within Spring Boot and it works with the in-memory metadata store. When I configure the JdbcMetadataStore using Postgres, Spring boot will no longer start and there is no error message other than Tomcat is shutting down. I am using Spring Boot with JPA and Spring WS
2018-10-22 11:16:06.098 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-10-22 11:16:06.106 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'metadataStore' has been autodetected for JMX exposure
2018-10-22 11:16:06.114 INFO 6775 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'metadataStore': registering with JMX server as MBean [org.springframework.integration.jdbc.metadata:name=metadataStore,type=JdbcMetadataStore]
2018-10-22 11:16:06.125 INFO 6775 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
I am using annotation based configuration
#Bean
public ConcurrentMetadataStore metadataStore(final DataSource dataSource) {
return new JdbcMetadataStore(dataSource);
}
#Bean
public SessionFactory<ChannelSftp.LsEntry> sftpSessionFactory() {
final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(this.host);
factory.setPort(this.port);
factory.setUser(this.username);
factory.setPassword(this.password);
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<>(factory);
}
#Bean
#InboundChannelAdapter(channel = "stream", poller = #Poller(fixedDelay = "5000"))
public MessageSource<InputStream> sftpMessageSource(ConcurrentMetadataStore metadataStore) {
final SftpStreamingMessageSource messageSource = new SftpStreamingMessageSource(template(), null);
messageSource.setRemoteDirectory("/");
messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(metadataStore,
"INT_"));
//messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(),
// "streaming"));
return messageSource;
}
#Bean
#Transformer(inputChannel = "stream", outputChannel = "data")
public org.springframework.integration.transformer.Transformer transformer() {
return new StreamTransformer();
}
#Bean
public SftpRemoteFileTemplate template() {
return new SftpRemoteFileTemplate(sftpSessionFactory());
}
I noticed it failed when trying to load the metadatastore to JMX. I then disabled JMX in Spring Boot and it fixed the issue. Not sure why it was failing to add the bean to JMX but disabling JMX in the spring boot property(yml) file fixed the issue.
spring:
jmx:
enabled: false

CamelContextStartedEvent called twice

The CamelContextStartedEvent is called twice for the same camel context (camel-1). The issue might be the way I register the EventNotifier. You can reproduce the issue with Spring Initializr with Spring Boot 1.5.14, Spring Boot Camel Starter 2.21.1 and Spring Boot Web Starter.
See the logs:
2018-07-06 11:04:41.104 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) is starting
2018-07-06 11:04:41.106 INFO 19092 --- [ main] o.a.c.m.ManagedManagementStrategy : JMX is enabled
2018-07-06 11:04:41.191 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.boot.RoutesCollector : Starting CamelMainRunController to ensure the main thread keeps running
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Total 0 routes, of which 0 are started
2018-07-06 11:04:41.194 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.090 seconds
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.216 INFO 19092 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 11223 (http)
2018-07-06 11:04:41.221 INFO 19092 --- [ main] com.example.bug.BugApplication : Started BugApplication in 4.684 seconds (JVM running for 6.773)
The service that initializes the EventNotifier:
#Service
public class SchedulerService {
private final CamelContext camelContext;
private final StartupEventNotifier startupEventNotifier;
public SchedulerService(CamelContext camelContext, StartupEventNotifier startupEventNotifier) {
this.camelContext = camelContext;
this.startupEventNotifier = startupEventNotifier;
}
#PostConstruct
public void init() {
camelContext.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
}
The EventNotifier:
#Component
public class StartupEventNotifier extends EventNotifierSupport {
private static final Logger logger = LoggerFactory.getLogger(StartupEventNotifier.class);
#Override
public void notify(EventObject event) throws Exception {
if (event instanceof CamelContextStartedEvent) {
logger.info("CamelContextStartedEvent for {}", event.getSource());
}
}
#Override
public boolean isEnabled(EventObject event) {
if (event instanceof CamelContextStartedEvent) {
return true;
}
return false;
}
}
application.yml:
camel:
springboot:
main-run-controller: true
server:
port: 11223
It is called twice, because it is registered twice. Once by you and once by Apache Camel. EventNotifier is registered automatically, if is found in Registry. Since your StartupEventNotifier is annotated as Component, it is part of Registry and Apache Camel registered it during CamelContext startup (You can see it in CamelAutoConfiguration line 424).
You have four options:
Remove your custom registration from SchedulerService.
Remove #Component annotation from StartupEventNotifier and register it with with camelContext.getManagementStrategy().addEventNotifier(new StartupEventNotifier())
Add duplicity check to your SchedulerService. Something like:
if (!context.getManagementStrategy().getEventNotifiers().contains(startupEventNotifier)){
context.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
Register EventNotifier in #PostConstruct of RouteBuilder. It will be registered before automatic discovery is started and then it will be skipped in CamelAutoConfiguration (See line 422)

Spring Boot Data Initialization

I am trying to insert some test data after my Spring Boot application has started. I have the below configuration in place. I do notice that the sql script is executed before the JPA entities are created resulting in a failure of the insert statement. Is there any other configuration I am missing here? As noted in my configuration I am using Spring Boot with H2 and EclipseLink for JPA.
Reference
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html
Configuration
# H2
spring.h2.console.enabled=true
# Datasource
spring.datasource.url=jdbc:h2:mem:testdb;MODE=ORACLE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
# JPA
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.properties.eclipselink.weaving=false
data.sql is placed under /src/main/resources
Logs
2017-09-05 20:37:37,989 [restartedMain ] INFO
o.s.j.d.e.EmbeddedDatabaseFactory - Starting embedded database:
url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false',
username='sa'
2017-09-05 20:37:38,141 [restartedMain ] INFO
j.LocalContainerEntityManagerFactoryBean - Building JPA container
EntityManagerFactory for persistence unit 'default'
2017-09-05 20:37:38,446 [restartedMain ] INFO
o.s.o.j.AbstractEntityManagerFactoryBean - Initialized JPA
EntityManagerFactory for persistence unit 'default'
2017-09-05 20:37:38,510 [restartedMain ] INFO o.s.j.d.i.ScriptUtils
- Executing SQL script from URL [file:/develop/src/data-init/target/classes/data.sql]
error...
Entity
#Entity
#Table(name = "TEMPLATE_CONFIG")
#Data
public class TemplateUser {
#Id
#Column(name = "TEMPLATE_CONFIG_ID", nullable = false)
private Long configId;
#Column(name = "APP_CODE", nullable = false, length = 100)
private String appCode;
...
}
Update
Uploaded a sample project:
https://git.io/v5SWx
Spring-Boot loads data.sql or data-${somthing}.sql
You can do:
spring.datasource.platform=h2.
spring.datasource.data=myscript-test.sql. ( locations can be changed with this property)
I have a project on that way and is working with h2.
And just how last alternative, if you are not able to load the information maybe you can use the CommandLineRunner in your application file with jdbc template.
This is an existing bug in Spring as confirmed here by the Spring Team.
https://github.com/spring-projects/spring-boot/issues/10365

Resources