Spring Data Neo4J and CDI - spring

I setup Spring Data Neo4J following this tutorial: http://spring.io/guides/gs/accessing-data-neo4j/ and changed this slightly to use it on the Neo4J server and this runs well.
Then I tried to find an example, how I can use the repositories within a CDI environment as outlined in these examples : http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpd.misc.cdi-integration
Merely, I can not find any example what I have to provide to make this run with Neo4J.
So my question is : did anybody try to setup Neo4j with Spring Data and CDI and can provide an example, how I have to set up Spring configuration for CDI and how I can make Repositories accessable for #Inject ? Please consider that I'm pretty new in the Spring Data and Neo4J topic ;)
Thanks in advance !
Joern

At least I found something that seems to work. I extended the Neo4JConfiguration to set up the Neo4J server connection. Within this class I produce also the needed repositories. The repositories itself have to be annotated with #NoRepositoryBean
public class MyNeo4JConfiguration extends Neo4jConfiguration {
GraphDatabaseService graphDatabaseService() {
return new SpringRestGraphDatabase("http://localhost:7474/db/data");
}
public GraphDatabase graphDatabase() {
if (graphDatabaseService() instanceof GraphDatabase)
return (GraphDatabase) graphDatabaseService();
return new DelegatingGraphDatabase(graphDatabaseService());
}
#Produces
PersonRepository getPersonRepository() {
GraphRepositoryFactory factory;
try {
factory = new GraphRepositoryFactory(new Neo4jTemplate(
this.graphDatabase()), this.neo4jMappingContext());
PersonRepository personRepository = factory
.getRepository(PersonRepository.class);
return personRepository;
} catch (Exception e) {
return null;
}
}
The repository :
#NoRepositoryBean
public interface PersonRepository extends GraphRepository<Person> {
Person findByName(String name);
Iterable<Person> findByTeammatesName(String name);
}
The PersonRepository can now be injected with #Inject.
Thanks to this post !!!

Related

Spring Boot Transaction support using #transactional annotation not working with mongoDB, anyone have solution for this?

Spring Boot version - 2.4.4,
mongodb version - 4.4.4
In my project, I want to do entry in 2 different document of mongodb, but if one fails than it should do rollback. mongodb supports transaction after version 4.0 but only if you have at least one replica set.
In my case I don't have replica set and also cannot create it according to my project structure. I can't use transaction support of mongodb because no replica-set. So, I am using Spring Transaction.
According to spring docs, to use transaction in Spring Boot, you only need to use #transactional annotation and everything will work(i.e. rollback or commit).
I tried many things from many sources but it is not rollbacking transaction if one fail.
Demo code is here,
This is demo code, not actual project.
This is my service class.
#Service
public class UserService {
#Autowired
UserRepository userRepository;
#Autowired
UserDetailRepository userDetailRepository;
#Transactional(rollbackFor = Exception.class)
public ResponseEntity<JsonNode> createUser(SaveUserDetailRequest saveUserDetailRequest) {
try {
User _user = userRepository.save(new User(saveUserDetailRequest.getId(), saveUserDetailRequest.getFirstName(), saveUserDetailRequest.getLastName()));
UserDetail _user_detail = userDetailRepository.save(new UserDetail(saveUserDetailRequest.getPhone(), saveUserDetailRequest.getAddress()));
} catch (Exception m) {
System.out.print("Mongo Exception");
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Also tried below code but still not working,
#EnableTransactionManagement
#Configuration
#EnableMongoRepositories({ "com.test.transaction.repository" })
#ComponentScan({"com.test.transaction.service"})
public class Config extends AbstractMongoClientConfiguration{
private com.mongodb.MongoClient mongoClient;
#Bean
MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
#Bean
public com.mongodb.MongoClient mongodbClient() {
mongoClient = new com.mongodb.MongoClient("mongodb://localhost:27017");
return mongoClient;
}
#Override
protected String getDatabaseName() {
return "test";
}
}
The transaction support in Spring is only there to make things easier, it doesn't replace the transaction support for the underlying datastore being used.
In this case, it will simply delegate the starting/committing of a transaction to MongoDB. WHen using a database it will eventually delegate to the database etc.
As this is the case, the pre-requisites for MongoDB still need to be honoured and you will still need a replica.

Spring - Choose repository implementation after bean creation

I'm developing Spring Boot application which persists data into MS SQL database. I'm tasked to add support for PostgreSQL, which uses same tables. So my goal is to add another repository layer implementation. But things gets little bit complicated.
It would be great if my repository layer could look like this:
public interface RecordRepository {
Record get(long id);
}
#Repository
#Conditional(MsSqlCondition.class)
public interface MsSqlRecordRepository {
public Record get(long id) {
// MS SQL implementation...
}
}
#Repository
#Conditional(PostgreSqlCondition.class)
public interface PostgreSqlRecordRepository {
public Record get(long id) {
// PostgreSql implementation...
}
}
However, it seems to not be possible in my case.
First of all, my application doesn't have database configuration in application.yaml file. It has to get these variables from remote HTTP server. My #Configuration file looks something like this:
#Configuration
public class MyAppConfiguration {
#Bean
public DatabaseConfiguration databaseConfiguration() {
// Make HTTP request to remote server
if (something) {
return new MsSqlServerConfiguration(...);
} else {
return new PostgreSqlServerConfiguration(...);
}
}
}
With this approach, I'm unable to use #Conditional annotation for my DataSource and repository beans, since #Conditional is evaluated while parsing #Configuration files. I need to choose right implementation AFTER DatabaseConfiguration bean is created.
I already considered this approach:
#Configuration
public class RepositoryConfiguration {
#Bean
public RecordRepository(DatabaseConfiguration configuration, JdbcTemplate jdbcTemplate) {
if (configuration.getType() == MS_SQL) {
return new MsSqlRecordRepository(jdbcTemplate);
} else {
return new PostgreSqlRecordRepository(jdbcTemplate);
}
}
}
But this seems that it is not working for me either, sice I'm using Spring AOP for my repository classes.
Does Spring Boot have some other mechanism, which allows me to choose right repository implementation after my DatabaseConfiguration bean is created?
Thanks

Error on injecting service: UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl

I am trying to inject service in spring boot app. However I'm getting following error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=RecommendationService,parent=RecommendationResourceImpl,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1163111460)
Here is the code:
package com.example.test.recommendations.resources;
#Provider
public class RecommendationResourceImpl implements RecommendationResource {
#Inject
private RecommendationService recommendationService;
#Override
public List<Recommendation> get(String currency,
String entity) {
return recommendationService.getRecommendations(currency, entity));
}
}
Service interface
package com.example.test.recommendations.resources;
// imports
public interface RecommendationService {
List<Recommendation> getRecommendations(String currency, String entity);
Recommendation get(UUID uuid);
}
Service implementation
package com.example.test.recommendations.resources;
//imports
#Component
public class RecommendationServiceImpl implements RecommendationService{
#Override
public List<Recommendation> getRecommendations(String currency, String entity) {
return Collections.emptyList();
}
#Override
public Recommendation get(UUID uuid) {
return null;
}
}
What is correct way to inject services in spring boot applications?
I am using spring boot version 1.3.8 and Jersey version 2.25.1
From your stacktrace it is evident that the server cannot find the dependency bean to be injected.So initially check that the desired bean for the class is getting created during applciation start up.Verify that the service class is in the classpath for component scan to take place, otherwise include the package for scanning.
You are using the #Inject annotation instead of the spring #Autowired annotation to inject the beans.It will work fine but the first and most important difference between #Autowired and #Inject annotation is that the #Inject annotation is only available from Spring 3.0 onwards, so if you want to use annotation-driven dependency injection in Spring 2.5 then you have to use the #Autowired annotation.
Secondly, use the annotation #Service for the service layer rather than using the #Component annotation.
Indicates that an annotated class is a "Service", originally defined
by Domain-Driven Design (Evans, 2003) as "an operation offered as an
interface that stands alone in the model, with no encapsulated state."
May also indicate that a class is a "Business Service Facade" (in the
Core J2EE patterns sense), or something similar. This annotation is a
general-purpose stereotype and individual teams may narrow their
semantics and use as appropriate.
This annotation serves as a specialization of #Component, allowing for
implementation classes to be autodetected through classpath scanning.
#Service
public class RecommendationServiceImpl implements RecommendationService{
#Override
public List<Recommendation> getRecommendations(String currency, String entity) {
return Collections.emptyList();
}
#Override
public Recommendation get(UUID uuid) {
return null;
}
}
I am not an expert on using jersey with springboot , so i do not know if any configurations are causing this issue.
Maybe this thread might be of help to you more:
Dependency injection with Jersey 2.0
You probably never registered your Service with the DI-container. You can do that in your ResourceConfig, which you probably have since you are using jersey:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
#Override
protected void configure() {
bind(RecommendationServiceImpl.class).to(RecommendationService.class).in(Singleton.class);
}
});
packages("com.example.test.recommendations.resources");
}
}
I am using hk2 without spring, so I usually annotate my interfaces with org.jvnet.hk2.annotations.Contract and the implementations with org.jvnet.hk2.annotations.Service. (note: not the spring #Service annotation), so I recommend trying that as well.

How to setup Spring Data JPA repositories without component scanning

For performance reasons I'm switching from component scanning to explicitly declaring my beans. So basically I want to remove #EnableJpaRepositories as it scans for repositories.
My repositories are standard interfaces extending JpaRepository. How can I declare my repositories?
You can create individual repository instances by declaring a JpaRepositoryFactoryBean manually:
#Configuration
class Config {
#Bean
public JpaRepositoryFactoryBean userRepository() {
JpaRepositoryFactoryBean factory = new JpaRepositoryFactoryBean();
factory.setRepositoryInterface(UserRepository.class);
return factory;
}
}
This will cause Spring to call getObject() to obtain the repository proxy from the factory and potentially inject it into clients.
However, I'd argue that - if not configured blatantly wrong - the overhead of scanning for repositories is neglectable, esp. compared to the time initializing an EntityManagerFactory takes.
I agree with #Oliver. However, in time API of Spring Data JPA apparently has changed and in the current version (2.2.3) the snippet should look more like below:
#Configuration
class Config {
#Bean
// assuming userId is String
public JpaRepositoryFactoryBean<UserRepository, User, String> userRepository() {
JpaRepositoryFactoryBean factory = new JpaRepositoryFactoryBean(UserRepository.class);
return factory;
}
}
If you only want to configure a concrete repository bean you can directly use the factory to create it like this:
#Configuration
public class NotificationConfig {
#Bean
public NotificationRepository notificationRepository(EntityManager entityManager) {
JpaRepositoryFactory jpaRepositoryFactory=new JpaRepositoryFactory(entityManager);
return jpaRepositoryFactory.getRepository(NotificationRepository.class);
}
}

How to use #Autowired to dynamically inject implementation like a factory pattern

I am fairly new to Sprint and am using Spring 3.x and roo1.1.1 for my application.
I have multiple implementation of an interface which would be #Autowired into other different classes. I would only be able to decide which implementation to go with at the runtime. This should be achieved with like a factory pattern.
public interface SomeInterface {
public void doSomething();
}
Implementation 1.
public class SomeOb implements SomeInterface {
public void doSomething() {
//Do something for first implementation here
}
}
Implementation 2.
public class SomeOtherOb implements SomeInterface {
public void doSomething() {
//Do something for first implementation here
}
}
Now in my service i needed this Autowired like
#Service
public class MyService {
#Autowired
SomeInterface ob;
//Rest of the code here
}
1) The logic to choose which implementation to be Autowired is only know runtime, so i cannot use the #Qualifier annotation to qualify this.
2) I tried to create a FactoryBean like
public class SomeFactoryBean implements FactoryBean<SomeInterface> {
#Override
public SomeInterface getObject() throws Exception {
if(/*Somecondition*/) {
return new SomeOb();
} else
return new SomeOtherOb();
}
#Override
public Class<? extends SomeInterface> getObjectType() {
if(/*Somecondition*/) {
return SomeOb.class;
} else
return SomeOtherOb.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
In the applicationContext.xml i have the tag mentioned.
When i run the webserver i run into an error like
No unique bean of type [com.xxxx.xxxx.SomeInterface] is defined: expected single matching bean but found 3: [xxxx, xxxxxxx, xxxxFactory]
Can anyone please help me to resolve this issue. If i am not doing this right please direct me to do this the right way.
Thanks and appreciate any help,
jjk
Thanks for the suggestion. I was able to solve the problem with help from a colleague. What i was doing wrong
I had the implementation of the SomeInterface with #Service. So this was picked up by the spring scanner and added to the bean.
During trial and error i removed the #Component annotation from by FactoryBean implementation.
After making these changes it worked like a charm.
return true from isSingleton() if you only need one implementation of the bean for a given instance of your application
But I question your design.
I would always use properties files to switch out implementations like this. I once had to implement CAPTCHA integration for a site. We were prototyping with the JCaptcah and ReCAPTCHA APIs. I created a new interface that contained just the functionality we needed and then created implementations for both APIs. Using a placeholders in the Spring configuration file and Maven profiles, we could switch out the implementation class at compile time or deployment time, for example, mvn jetty:run -DcaptchaImpl=recaptcha or -DcaptchaImpl=jcaptcha.
Without knowing the task that you want to accomplish, it's hard to provide more advice.

Resources