NoUniqueBeanDefinitionException with #EnableExperimentalNeo4jRepositories annotation and SpringBoot 1.4.2 - spring-boot

I'm having an issue with Spring boot 1.4.2.M1 and #EnableExperimentalNeo4jRepositories.
It seems to be a conflict between two beans, one spring boot, one spring-data-neo4j.
Here is a stack trace excerpt:
18:12:15.891 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.neo4j.ogm.session.Session' available: expected single matching bean but found 2: getSession,org.springframework.data.neo4j.transaction.SharedSessionCreator#0
And another...
Parameter 0 of method setSession in org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean required a single bean, but 2 were found:
- getSession: defined in BeanDefinition defined in class path resource [org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration$SpringBootNeo4jConfiguration.class]
- org.springframework.data.neo4j.transaction.SharedSessionCreator#0: defined by method 'createSharedSession' in null
Anybody have any idea how to solve this?
Below is my Neo4j Configuration
package com.domain.core.context;
import javax.annotation.PostConstruct;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.event.Event;
import org.neo4j.ogm.session.event.EventListenerAdapter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableExperimentalNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Configuration
#ComponentScan("com.domain")
#EnableExperimentalNeo4jRepositories(basePackages = "com.domain.core.repository")
#EnableTransactionManagement
#SpringBootApplication(exclude = Neo4jDataAutoConfiguration.class)
public class TestPersistenceContext {
#PostConstruct
public void init() {
log.info("TheScene.Co: Initializing Test Neo4jConfig ...");
}
#Bean
public Neo4jTransactionManager transactionManager() throws Exception {
return new Neo4jTransactionManager(sessionFactory());
}
#Bean
public SessionFactory sessionFactory() {
return new SessionFactory(getConfiguration(), "com.domain") {
#Override
public Session openSession() {
Session session = super.openSession();
session.register(new EventListenerAdapter() {
#Override
public void onPreSave(Event event) {
// do something - like set an id on an object
log.debug("***** Saving domain object ********");
}
});
return session;
}
};
}
#Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config.driverConfiguration().setCredentials("neo4j", "password")
.setDriverClassName("org.neo4j.ogm.drivers.http.driver.HttpDriver");
return config;
}
}

You must be using Spring Data Neo4j (SDN) version 4.2.0.M1. This milestone release was put out to get feedback on several big changes from 4.1.x.
SDN 4.2.0.RC1 should be out later this week but for now 4.2.0.BUILD-SNAPSHOT is actually quite stable in the lead up to Ingalls release train for Spring Data in Decemeber.
I have written a guide for users coming from SDN 4.0/4.1 which goes over how to upgrade to the snapshot build.
In this guide there is a link to an example project branch which shows how to get this version to work with Spring Boot 1.4.x with a few minor work arounds.
WIth the upcoming release of Spring Boot 1.5, we have updated all the autoconfiguration to work straight out of the box with SDN 4.2. We will update the documenation for Spring Boot closer to release.

Related

spring-boot-starter-jdbc DAO repository object not injected in working legacy webservice

I am new in the spring/boot word and have a working JAX-WS based web-service declared in a springboot project. It is started and configured via web.xml and sun-jaxws.xml. So, no beans included there only endpoints declarations and servlet definitions and mappings.
I just now want to save the items i get in the webservice into the mysql database using spring-boot-starter-jdbc which is not working:
I can't achieve this as the repository is not injected in the webservice implementation.
Followed all steps in other question, but not achieving this!
Normally declaration of the datasource parameters in application.properties and annotating #webservice and #Repository would suffice to get the injection of the repository working in the webservice class. What am i missing ?
Here details of the steps I followed:
the webservice implementation is a package X and i created a #SpringBootApplication in order to use a mysql datasource declared in application.properties.
So i annotated the webservice as a #Component and the data access repository with #Repository and #Component
parent version: spring-boot-starter-parent : 1.5.10.RELEASE
webservice service implementation:
BServiceManager.java
package X;
....
#Component
#WebService(name = "***",***)
#BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
#XmlSeeAlso({
packagesxxx.class,
....
})
public class BServiceManager
implements xxxxx
{
....
#Autowired
private ItemRepository irepo;
....
#WebMethod(**)
#WebResult(***)
public ResponseDataInfo sendInfo( ){
....
trepo.saveitem(item)
....
}
}
ItemRepository.java
package Y.Z;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Component
#Repository
public class ItemRepository {
#Autowired
private JdbcTemplate jdbcTemplate ;
....
public boolean saveitem(Item item) {
....
}
}
Item.java
package Y.Z;
public class Item {
....
}
GetItemsApplication
package Y;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//#ComponentScan(basePackages={"Y","Y.Z","X"})
#SpringBootApplication
public class GetItemsApplication {
....
public static void main(String[] args) {
SpringApplication.run(GetItemsApplication.class, args);
log.info("--Spring Boot inits done--");
}
}
application.properties
spring.data.jpa.repositories.enabled=false
spring.data.jdbc.repositories.enabled=true
# MySQL properties
spring.datasource.url=****
spring.datasource.username=****
spring.datasource.password=****
....
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
logging.level.org.springframework.jdbc.core.JdbcTemplate=debug
NB: even having datasource bean is not helping :
File: DataSourceConfig.java
package Y.Z;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
//#EnableJdbcRepositories for Spring
#Configuration
public class MDataSourceConfig {
#Bean
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
return dataSourceBuilder.build();
}
#Bean
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
Your Webservice doesn't seem to get created by Spring.
Therefore Spring has no control over its dependencies, so you have to get the dependency programmatically.
There are many ways to do this.
Easy but not very elegant and uses global variables which might cause problems, especially with tests: https://stackoverflow.com/a/18486178/66686
More elegant but requires weaving Spring autowiring using #Configurable

How to enable connection pooling in spring boot embedded tomcat

I have a spring boot application which is not a web application. In this application i have configured embedded tomcat with the help of following bean.
#Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatWebServer(tomcat);
}
protected void postProcessContext(Context context) {
ContextResource contextResource = new ContextResource();
contextResource.setName("jdbc/BPMDB");
contextResource.setType(DataSource.class.getName());
contextResource.setProperty("driverClassName", env.getProperty("bpm.db.driverClassName"));
contextResource.setProperty("url", env.getProperty("bpm.db.url"));
contextResource.setProperty("username", env.getProperty("bpm.db.username"));
contextResource.setProperty("password", env.getProperty("bpm.db.password"));
context.getNamingResources().addResource(contextResource);
}
};
}
How do i do connection pooling for this embedded tomcat. I am using spring boot 2.x which says hikaricp is the default connection pooling but how to set it into this embedded tomcat.
Does this require to set properties like spring.datasource.hikari.initial-size=15
spring.datasource.hikari.max-wait=20000
but again how boot will know and how will i know that these properties are used.
Thanks.
I have got answer for my problem.
Its simple. We just have to make a DataSource reference and autowire it and mention database related properties along with hikari related properties.
Code is below.
#Autowired
public DataSource dataSource;
Add above to your #Configuration marked class and add following properties to application.properties file.
spring.datasource.driver-class=...
spring.datasource.url=jdbc:oracle:thin:....
spring.datasource.username=..
spring.datasource.password=..
spring.datasource.hikari.initial-size=15
spring.datasource.hikari.max-wait=20000
spring.datasource.hikari.max-active=50
spring.datasource.hikari.max-idle=50
spring.datasource.hikari.min-idle=8
Also i have written a test case to check for hikari connection pool. Below is the code.
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(
properties = "spring.datasource.type=com.zaxxer.hikari.HikariDataSource",
classes = {ApplicationConfiguration.class,PersistenceJpaContext.class}
)
public class HikariConnectionPoolTest {
#Autowired
private DataSource dataSource;
#Test
public void hikariConnectionPoolIsConfigured() {
assertEquals("com.zaxxer.hikari.HikariDataSource", dataSource.getClass().getName());
}
}

Error Messages as Key Value Pairs - from a Properties File in classpath - Spring boot 2.0

We are currently on a Spring Boot Version 1.x
We have Error Messages (Error Key -> Error Code) pairs in our error.properties file (this is in the class path).
We leveraged PropertiesConfigurationFactory to get these Error Key and Error Code pairs in to a POJO, this POJO had a Map
Hence very convenient to be used across our application to get an Error code for a given Error Key.
What is its equivalent in Spring Boot 2.x ?.
Assuming you have error.properties file with the below contents:
errors.error1=101
errors.error2=102
errors.error3=103
A simple spring boot app that demonstrates the injection of these properties :
package snmaddula.remittance;
import java.util.Map;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
#SpringBootApplication
#ConfigurationProperties
#PropertySource("classpath:error.properties")
public class DemoApplication {
private Map<String, Integer> errors;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public CommandLineRunner cli() {
return (args) -> {
System.out.println(errors); // you can print and see the error properties injected to this map.
};
}
public void setErrors(Map<String, Integer> errors) {
this.errors = errors;
}
}
With the use of #PropertySource and #ConfigurationProperties we can enable property injection provided we have a setter method for our attribute.
When you run this program, you can see the properties getting printed on to the console as I added a CommandLineRunner cli() {..} to show the working of it.
The working sample is available on GitHub.

Spring Boot NoOp Fallback Bean

Following code works like expected.
When a MailSender is available in the context an EmailService is created.
When no MailSender is available the NoopEmailSender is created.
From my understanding Spring Boot prefers the method with the most parameters when they have the same names. Unfortunately I can not find this behavior described somewhere in the documentation or JavaDoc.
My issue is that I'm not sure if the code works just because of "luck"/"random" or this behavior is intended.
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.MailSender;
#Configuration
#Slf4j
public class MailConfiguration {
#Bean
public EmailSender emailSender(MailSender mailSender) {
return new EmailService(mailSender);
}
#Bean
public EmailSender emailSender() {
log.info("Email sending is not configured.");
return new NoopEmailSender();
}
}
Thanks for the help!

Loading properties using #Value into a BeanFactory object using #Bean in Spring Boot

Can anyone help me with a Spring Boot problem?
I want to create a factory bean as part of my application context but I want to be able to instantiate it with injected property values. However it seems that Spring will load FactoryBeans before anything else as demonstrated here:
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ListFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
#EnableAutoConfiguration
public class TestClass
{
#Value("${test.value}")
String value;
#Bean
public Object test1()
{
System.out.println("test.value=" + value );
List<String> list = new ArrayList<String>();
ListFactoryBean factory = new ListFactoryBean();
factory.setSourceList(list);
return factory;
}
public static void main(String[] args)
{
SpringApplication.run(TestClass.class, args);
}
}
When run with
java -Dtest.value=HELLO -jar myTest.jar
It loads in the value correctly:
test.value=HELLO
However, when I specify that the bean to be loaded is in fact a factory bean, and run it in the same way:
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ListFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
#EnableAutoConfiguration
public class TestClass
{
#Value("${test.value}")
String value;
#Bean
public AbstractFactoryBean test1()
{
System.out.println("test.value=" + value );
List<String> list = new ArrayList<String>();
ListFactoryBean factory = new ListFactoryBean();
factory.setSourceList(list);
return factory;
}
public static void main(String[] args)
{
SpringApplication.run(TestClass.class, args);
}
}
The value is null because it hasn't been injected yet.
test.value=null
Is there any way around this?
Thanks
Spring often has to query bean definitions for the type of object they produce. Factory beans are always problematic because they can cause dependency cascades in a futile attempt to resolve all dynamic information available before asking for the type.
I think ListFactoryBean is insufficiently precise about its product type (getObjectType() can only return a non-generic List.class). You might be able to write your own factory that is parameterized with the correct generic type. Or you might get away with just declaring the #Bean to return a FactoryBean<List<String>.
Another tip is to move the #Bean definition to a separate class (e.g. a nested static one) so that it can be instantiated independently of the rest of the application context. E.g.
#EnableAutoConfiguration
public class TestClass
{
protected static class NestedConfiguration {
#Value("${test.value}")
String value;
#Bean
public FactoryBean<Properties> test1()
{
System.out.println("test.value=" + value );
// ...
return factory;
}
}
...
}
Not really a Boot question this one so you might consider changing the tags.
Take look at Empowering your apps with Spring Boot's property support
There is new annotation #EnableConfigurationProperties in Spring Boot Actuator
The Spring Environment is a collection of name-value pairs taken from (in order of decreasing precedence)
1) the command line,
2) the external configuration file,
3) System properties,
4) the OS environment.
There is also possible to define application properties (external configuration) in YAML format.

Resources