Elasticsearch spring implementation error - java

I have a interface which has function used to query ElasticSearch. It extends the ElasticsearchRepository for doing it.
public interface HouseholdRepository extends ElasticsearchRepository<SearchHouseholdESBean, String> {
List<SearchHouseholdESBean> findByPhoneNumberAndActiveInd(String phoneNumber, String activeInd);
The problem is how do i call this in my business class where i need to get the results. This being an interface , i can't create an object of this to call the methods. Also, the implementation is implicit to the jars in the Elastic Search.

To use elastichsearch repositories you must follow the next steps:
1. add annotation #EnableElasticsearchRepositories on your SpringBootApplication
#SpringBootApplication
#EnableElasticsearchRepositories
public class Application {
//...
2. Make sure that the interface HouseholdRepository is scanned by the spring-boot application. You can simple achieve this by placing it under the same root package as your Application class.
3.You will just #Autowire HouseholdRepository in your service without further changes. The idea behind spring boot data is that the code will be generated based on that interface.
OBS: make sure that you have the proper project dependencies. You should depend on spring-boot-starter-data-elasticsearch to avoid extra configuration effort.

Related

Spring generates two beans of the same instance "MyRepository"

i'm fairly 'new' to Spring Boot and need a bit of help with CrudRepositories.
My problem is the following: When I want to start my Spring Boot Application, it starts just fine, creates all the tables in the database, but somehow manages to fail, because Spring creates two beans of the same interface:
Note that my package hierarchy looks a bit different. Spring Boot however is referencing the exact same interface, twice.
The bean 'IMyRepository', defined in com.package.IMyRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration, could not be registered. A bean with that name has already been defined in com.package.IMyRepository defined in #EnableJdbcRepositories declared on JdbcRepositoriesRegistrar.EnableJdbcRepositoriesConfiguration and overriding is disabled.
For clarification: I do not have two interfaces declared wit the same name, I do not have any MyRepositoryImpl classes, and I do not have multiple projects with the same hierarchy. (only one: src/main/.../com.(...).IMyRepository)
My Repository interface looks like this:
package com.package.api.components.account.repository;
import com.package.api.components.account.entity.Account;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface IMyRepository extends CrudRepository<Account, Long> {
Account findByEmail(String email);
Account findByEmailAndPassword(String email, String password);
}
And the only single time where, I am taking usage of IMyRepository is in this class:
#Component
#AllArgsConstructor
public class AccountService implements IAccountService, IRegisterService, ILoginService {
private final IAccountRepository accountRepository;
private final IPasswordValidationService passwordValidationService;
private final AAccountMapper accountMapper;
// Code
}
Here are some answers on StackOverflow & co I've already tried, which none off them worked for me:
https://coderanch.com/t/747155/java/bean-defined-myRepository
Spring Boot detects 2 identical repository beans
Thanks you very much for reading this!
Don't put #Repository (or #Component) on the interface, only on the implementation.
As stated in the comments of #M. Deinum, the problem was, that (in my case) I had two spring-boot-starter-data-... dependencies, both of which wanted to create beans of the same class/interface, with the same Impl name.
I solved the problem, by following their instructions:
I deleted the dependency spring-boot-starter-data-jdbc
I also deleted the library from the project and classpath
Another problem was, that my project wouldn't keep running. I, again, solved this problem by following their instructions:
I added the spring-boot-starter-web dependency

How to #Autowire services in SpringBoot

Good day, guys. I have a question about autowiring services into my classes when using Springboot. All of the examples I have seen on the Internet as well as in the Springboot specification do something of the like (taking an excerpt from the Springboot version 1.5.7 specification):
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
#Autowired
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
This is a class that injects a property through its constructor, by means of #Autowiring the constructor. Another form is to #Autowire the property like this:
#Autowired
private final RiskAssessor riskAssessor
But, where I work, for these two methods to work, I have been told that I need to use this method:
applicationContext.getAutowireCapableBeanFactory().autowireBean(Object.class)
They have told me that I need this in order for the #Autowired annotation to work.
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly? (Something like #AutowiredClass). The above method is too verbose and hard to remember, so surely there must be a better way to make #Autowired work on classes in order to inject services, just like we do in Grails where we just say def someService and it is automatically injected.
If you want properly use #Autowired in your spring-boot application, you must do next steps:
Add #SpringBootApplicationto your main class
Add #Service or #Component annotation to class you want inject
Use one of two ways that you describe in question, to autowire
If you don't have any wiered package structure and the main class package includes all other classes you want spring to instantiate (directly or in the subpackages) a simple annotation #ComponentScan on your main class will help you save all those boiler plate code. Then spring will do the magic, it will go and scan the package(and subpackages) and look for classes annotated with #Service, #Component etc and instantiate it.
Even better, use #SpringBootApplication in your main class, this will cover #Configuration as well. If it is a green field project , I would encourage to start from start.spring.io - a template generation/scaffolding tool for spring
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly?
There is: #SpringBootApplication
If you put this at the root of your application (file that contains the main class) and as long as your services are at the same package or a sub-package, Spring will auto-discover, instantiate, and inject the proper classes.
There's an example in this walk-through: REST Service with Spring Boot
As described in that page:
#SpringBootApplication is a convenience annotation that adds all of the following:
#Configuration tags the class as a source of bean definitions for the application context.
#EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
#ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
You need to annotate the implementation of RestService as a #Service or #Component so Spring would pick it up.
#Service
public class MyRiskAssessorImpl implements RiskAssessor {
///
}
#Autowired almost works out of the box. Just do your component scanning of the class you want to autowire and you are done. Just make sure your main class (or main configuration class) uses #ComponentScan("{com.example.app}") or #SpringBootApplication (main class). The docs explain this stuff pretty good

REST API Autowire remote or local implementation of a service automatically

I have a REST API built on Spring Boot consisting of 2 seperate web services. I don't know if those two web services will be hosted on the same machine so I want to make remote and local implementation for all services. Example below:
Local service implementation:
public class LocalExampleService implements ExampleService{
public Item getItem(long id){
//Get item using implementation from another local project
}
}
Remote service implementation:
public class RemoteExampleService implements ExampleService{
#Value("${serviceURL}")
private String serviceURL;
public Item getItem(long id){
//Get item calling remote service
}
}
Controller:
public class MyController{
#Autowired
private ExampleService exampleService;
}
Web service has many services with local and remote implementation and I want to let Spring know which type of implementation it should choose for all services.
I've been thinking about putting url in properties file and during intialization the app would check whether properties contain url and then autowire service approprietly. But then I would have to write logic for every service autowiring.
What's the best option to autowire correct service implementation automatically?
You can use Spring profiles to control which version of implementation should be used via spring properties.
In spring properties add below entry
spring.profiles.active=NAME_OF_ACTIVE_PROFILE
Every service implementation needs profile annotation. That's how your services implementation should look like:
#Component
#Profile("local")
public class LocalExampleService implements ExampleService{}
#Component
#Profile("remote")
public class RemoteExampleService implements ExampleService{}
If your project needs to use local implementation of a service then in properties instead of NAME_OF_ACTIVE_PROFILE insert local otherwise remote.
For fully automatic auto-wiring you need to add method running at the startup that checks whether local implementation class exists and then set profile properly. To do this you need to modify code in spring boot main method:
public static void main(String[] args){
String profile = checkCurrentProfile(); //Method that decides which profile should be used
System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, profile);
SpringApplication.run(MyApplication.class, args);
}
If you choose this approach then you don't need previous entry in properties file.
My attempt to implement something like this https://github.com/StanislavLapitsky/SpringSOAProxy
The idea is to check if a spring bean cannot be found locally then automatically create a Proxy which uses RestTemplate internally to call the same service remotely.
You need to define contract - services interfaces plus DTO and define URL resolver to specify which URL should be used for each service.

Instantiating variables in Controller on start of application using Play Framework

I am using Java through the Play Framework to implement an API. I am trying to instantiate a few variables on the start of the application that should last for the entire life of the application and that are to be used in my HomeController.
These variables are objects that can be used to call functions from a specific class.
I have read that the best way to implement code that executes on the start of the application is to use Dependency Injection but I did not understand how to do it.
Can you please clarify how this is done?
Thank you.
The example on Dependency Injection uses Google Guice. The first is to include that dependency on the build.sbt file.
you can do that by adding
// https://mvnrepository.com/artifact/com.google.inject/guice
libraryDependencies += "com.google.inject" % "guice" % "4.1.0"
You can then choose to extend GlobalSettings (https://www.playframework.com/documentation/2.5.x/GlobalSettings) and choose to inject a Guice injector
An example of the implementation is here : https://dzone.com/articles/guicing-play-framework
Hope it helps
You can find here and here more examples of dependency injection in Play.
After you got the idea, it should be easy to implement.
To define an object, that should last for the application entire lifecycle:
Define the class (of such object) with #Singleton annotation:
#Singleton
public class MyClass4AppLifecycle {
public MyClass4AppLifecycle() {
...
}
....
}
Add to the controller a data member with #Inject annotation:
public class MyController extends Controller {
#Inject
private MyClass4AppLifecycle myGlobalObject;
...
Note: since you mentioned several objects, member inject annotation seems more appropriate, that a constructor annotation.
Register you class for dependency injection in the default module (it is the simplest way):
public class Module extends AbstractModule {
#Override
protected void configure() {
bind(MyClass4AppLifecycle.class).asEagerSingleton();
}
}
Repeat the three above for each type you need to have globally

Spring Data CrudRepository and Transactions

I'm trying to implement transactions on a CrudRepository Interface. I'm a beginner with this and my current problem is that when receiving a lot of requests from different clients, I'm sometimes getting a duplicate.
To avoid that I wanted to use SQL Transactions and their implementation with Spring but I'm unable to get it working.
Here is how I've tried to do it :
#Repository
#EnableTransactionManagement
#Transactional
public interface ApplicationPackageDao extends CrudRepository<ApplicationPackage, Long> {
/**
* Find if a record exists for this package name ,
* #param packageName
* #return
*/
#Transactional
ApplicationPackage findByPackageName(String packageName);
}
However it doesn't seem to work.
I tried to add the #Transactionnal annotations earlier in the Java methods I'm calling but I can't get it working either.
How am I supposed to work with transactions on CrudRepository ?
Or am I using completely the wrong thing?
In addition to crm86's answer some more notes to the #Transactional annotation:
It seems to be best practice to annotate the entry points into your application (e.g. your web controller methods or the main method of a scheduled batch). By using the annotation attribute TxType you can ensure constraints/conditions in methods which are located deeper in your application (e.g. TxType.MANDATORY would throw if no trx-context is running, etc.).
The #Transactional annotation has only an effect if the class is loaded as spring bean (e.g. #Component annotation at class level).
Remember that only RuntimeException's lead to a rollback. If you want a checked Exception leading to a rollback you have to enumerate each such Exception by using the attribute rollbackOn.
The annotation at class level is valid for all public methods of this class. Method level annotations override those at the class level. The repeated annotation in your example above (first at class level, then at method level) has no effect.
What I suggest:
Check your context and configuration classes with #Configuration annotation. From the documentation:
The #EnableTransactionManagement annotation provides equivalent
support if you are using Java based configuration. Simply add the
annotation to a #Configuration class
#EnableTransactionManagement and only looks
for #Transactional on beans in the same application context they are
defined in
Then you could use #Transactional in your service even in a method
Hope it helps

Categories