I'm creating an application based on Hazelcast and spring-boot-starter-web. The application structure is:
Book controller-> BookService interface-> BookServiceImplementation-> put into hazelcast queue
Author controller-> AuthorService interface-> AuthorServiceImplementation-> put into hazelcast queue.
For that purpose i need one class that contains hazelcastInstance to share it in all services so i created blackboard interface but because i use #Autowired it is creating new instance for every service and i need to set hazelcast instance again.
My code so far:
Controller:
#GetMapping("book")
public ResponseEntity<Void> getBookDetails(
#RequestParam(value = "bookId", required = false) Long bookId) {
bookService.add(bookId);
return new ResponseEntity<Void>(HttpStatus.OK);
}
Service impl:
#Service("bookService")
public class BookServiceImpl extends BaseService implements BookService {
#Override
public void add(Long bookId) {
blackboard.add(bookId, Listeners.BOOK_QUEUE_NAME);
}
BaseService:
public class BaseService {
#Autowired
protected Blackboard blackboard;
public void loadInstance(ClientConfig clientConfig) {
HazelcastInstance hazelcastInstanceClient = HazelcastClient.newHazelcastClient(clientConfig);
blackboard.setHazelcastInstance(hazelcastInstanceClient);
}
}
Blackboard interface impl:
#Component("blackboard")
public class BlackboardImpl implements Blackboard {
private HazelcastInstance hazelcastInstance;
#Override
public HazelcastInstance getHazelcastInstance() {
return hazelcastInstance;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
#Override
public boolean add(Object obj, String collectionId) {
IQueue<Object> queue = hazelcastInstance.getQueue(collectionId);
return queue.add(obj);
}
}
Related
I have a project in spring boot and I'm using CrudRepository, but when I try to update, it doesn't do anything.
#Entity
public class PfmSelection implements Serializable{
#Id
private Integer releaseId;
private String preparedBy;
}
Repositiry
#Repository
public interface IPfmSelectionDao extends CrudRepository<PfmSelection, Integer> {
}
Service
public interface IPfmSelectionService {
public PfmSelection save(PfmSelection pfmSelection);
public PfmSelection findById(Integer id);
}
Service Impl
#Service
public class PfmSelectionService implements IPfmSelectionService {
#Autowired
private IPfmSelectionDao pfmSelectionDao;
#Override
#Transactional
public PfmSelection save(PfmSelection pfmSelection) {
return this.pfmSelectionDao.save(pfmSelection);
}
#Override
#Transactional(readOnly = true)
public PfmSelection findById(Integer id) {
return this.pfmSelectionDao.findById(id).orElse(null);
}
}
Service where I use the other Service
#Autowired
private IPfmSelectionService pfmSelectionService;
private void updatePfm(PushModel pushModel) {
PfmSelection pfm = this.pfmSelectionService.findById(167427);
pfm.setPreparedBy("Rodrige");
pfmSelectionService.save(pfm);
}
I don't receive any error in the console.
You need to take a few steps to know what the problem is
Take the return of pfmSelectionService.save(pfm) and print the saved instance returned like below:
private void updatePfm(PushModel pushModel) {
PfmSelection pfm = this.pfmSelectionService.findById(167427);
pfm.setPreparedBy("Rodrige");
PfmSelection pfm2 = pfmSelectionService.save(pfm);
System.out.println(pfm2.getPreparedBy());
}
Put logger/debugger inside the save method, before and after the save method and check for the entry/exit sop/logger statements in log/console like
#Override
#Transactional
public PfmSelection save(PfmSelection pfmSelection) {
System.out.println("Inside save method");
PfmSelection pfmSelectionSaved =
this.pfmSelectionDao.save(pfmSelection);
System.out.println("Exits save method");
return pfmSelectionSaved;
}
Check for any Aop around advice or any place where the exception is being caught but eaten/not thrown further.
Check if there is any update query fired in the logs at the time of save call.
Also check if the setter method pfm.setPreparedBy("Rodrige"); is Empty?
I have a very difficult time trying to implement Dagger2 to my android app.
In my app I use RoomDB. In the beginning, I used one MainActivity class and I have successfully implemented RoomDB. It worked as aspected. I could set and get values from my database. However, later I decided to expand my app by moving my logic from MainActivity class to fragments where each fragment is identical just it writes data or gets data from a database based on a different type of product. I have tried to make this work by implementing dependency injection Dagger2. I have watched plenty of videos and read a bunch of articles on how to do this however no luck so far.
I tried to implement one example based on the article Integrate Dagger 2 with Room Persistence Library in few lines
In order not to destroy my existing application I have created a new project with the same structure as in the article. in the new project, I have used the same data structure as I have in my application. The application builds successfully. However, I can't retrieve my data from the database and I don't know why.
Here is what I did:
Product.class
#Entity(tableName = "product_table")
public class Product implements Serializable {
#PrimaryKey(autoGenerate = true)
private int ID;
#ColumnInfo(name = "product_count")
private String count;
#ColumnInfo(name = "time")
private String time;
#ColumnInfo(name = "p_type")
private String product_type;
public String getProduct_type() {
return product_type;
}
public void setProduct_type(String product_type) {
this.product_type = product_type;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
ProductDao
#Dao
public interface ProductDao {
#Insert(onConflict = REPLACE)
void insert(Product product);
#Delete
void delete (Product product);
#Delete
void reset(List<Product> product);
#Query("UPDATE product_table SET product_count=:sCount WHERE ID = :sID")
void update(int sID, String sCount);
#Query("SELECT * FROM product_table")
List<Product> getAll();
#Query("SELECT SUM(product_count)FROM product_table WHERE p_type = 'used' ")
String getProductTotalCount();
}
AppComponent
#Singleton
#Component(dependencies = {}, modules = {AppModule.class, RoomModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
ProductDao productDao();
DemoDatabase2 demoDatabase2();
ProductRepository productRepository();
Application application();
}
AppModule
#Module
public class AppModule {
Application mApplication;
public AppModule(Application application) {
mApplication = application;
}
#Provides
#Singleton
Application providesApplication() {
return mApplication;
}
}
RoomModule
#Module
public class RoomModule {
private DemoDatabase2 demoDatabase2;
public RoomModule(Application mApplication) {
demoDatabase2 = Room.databaseBuilder(mApplication, DemoDatabase2.class, "demo-db").build();
}
#Singleton
#Provides
DemoDatabase2 providesRoomDatabase() {
return demoDatabase2;
}
#Singleton
#Provides
ProductDao providesProductDao(DemoDatabase2 demoDatabase2) {
return demoDatabase2.getProductDao();
}
#Singleton
#Provides
ProductRepository productRepository(ProductDao productDao) {
return new ProductDataSource(productDao);
}
}
DemoDatabase2
#Database(entities = {Product.class}, version = DemoDatabase2.VERSION, exportSchema = false)
public abstract class DemoDatabase2 extends RoomDatabase {
static final int VERSION = 2;
public abstract ProductDao getProductDao();
}
ProductDataSource
public class ProductDataSource implements ProductRepository {
private ProductDao productDao;
#Inject
public ProductDataSource(ProductDao productDao) {
this.productDao = productDao;
}
#Override
public void insert(Product product) {
}
#Override
public void delete(Product product) {
}
public String provideProductCount() {
return productDao.getProductTotalCount();
}
#Override
public List<Product> getAll() {
return productDao.getAll();
}
}
ProductRepository
public interface ProductRepository {
void insert(Product product);
void delete(Product product);
List<Product> getAll();
String provideProductCount();
}
MainActivity
public class MainActivity extends AppCompatActivity {
#Inject
public ProductRepository productRepository;
TextView mTextView;
EditText mEditText, mEditTextType;
Button mButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppComponent.builder()
.appModule(new AppModule(getApplication()))
.roomModule(new RoomModule(getApplication()))
.build()
.inject(this);
mTextView = findViewById(R.id.text);
mEditTextType = findViewById(R.id.product_type);
mEditText = findViewById(R.id.productCount);
mButton = findViewById(R.id.button);
}
public void addValue(View view) {
Product product = new Product();
String count = mEditText.getText().toString();
product.setCount(count);
String type = mEditTextType.getText().toString();
product.setProduct_type(type);
mTextView.setText(String.valueOf(product.getCount()));
}
}
How can I get or set data as provideProductCount() from my DB? As if I try to use something like
String producCount = productRepository.provideProductCount();
It gives error as:
Caused by: java.lang.IllegalStateException: A migration from 1 to 2 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.
at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:117)
How to fix this?
You have to use fallbackToDestructiveMigration() to allow Room recreate database when you change db
public RoomModule(Application mApplication) {
demoDatabase2 = Room.databaseBuilder(mApplication, DemoDatabase2.class, "demo-db")
.fallbackToDestructiveMigration()
.build();
}
Visit here for more detail
First of all, As I can see your error doesn't relate to the Dagger. For migrating the database check this link:
https://developer.android.com/training/data-storage/room/migrating-db-versions
And the way you provided the context for creating the database is wrong.
I built a demo project with Dagger, RoomDB, but It was written by Kotlin.
https://github.com/frank-nhatvm/expensestracker
I hope that can help you. Check in the di/AppComponent.kt to know to provide a context using Dagger.
I'm trying to use the default aop proxy provided by Spring, but i'm getting an execption error.
Here is my code:
A first class that run the test example.
#EnableAspectJAutoProxy()
#ComponentScan(basePackageClasses = {MyDaoRepository.class, MyService.class,MyAdvices.class})
#Configuration
public class SpringAdvices {
public static void main( String[] args ) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringAdvices.class);
service myService = ctx.getBean(MyService.class);
Person p1 = (Person) ctx.getBean("person");
myService.save(p1);
}
#Bean
public Person person(){
return Person.builder()
.name("Bagna")
.age(52)
.profession(null)
.dateOfBirth(LocalDate.of(1950,12,13))
.build();
}
}
A second class that represent my advices:
#Aspect
#Component
public class MyAdvices {
#Before("execution(boolean *.dao.save(..))")
public void beforesavamethod(){
System.out.println("beforesavamethod");
}
#After("execution(boolean *.dao.save(..))")
public void aftersavamethod(){
System.out.println("aftersavamethod");
}
}
My service and repository classes:
#Service
public class MyService implements service {
#Autowired
MyDaoRepository myDaoRepository;
#Override
public boolean save( Person person ){
return this.myDaoRepository.save(person);
}
#Override
public boolean delete(Person person){
return this.myDaoRepository.delete(person);
}
}
public interface service {
public boolean save( Person person );
public boolean delete( Person person );
}
#Repository
public class MyDaoRepository implements dao {
List<Person> personList = new ArrayList<>();
#Override
public boolean save( Person person ){
return this.personList.add(person);
}
#Override
public boolean delete( Person person ){
return this.personList.remove(person);
}
}
public interface dao {
public boolean save( Person person );
public boolean delete( Person person );
}
The exceptin I'm getting concern the injection of the dao object to the service object.
UnsatisfiedDependencyException: Error creating bean with name
'myService': Unsatisfied dependency expressed through field
'myDaoRepository'; nested exception is
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean
named 'myDaoRepository' is expected to be of type
'aop.question_005.dao.MyDaoRepository' but was actually of type
'com.sun.proxy.$Proxy22'
I can solve this problem by enabling the GCLIB mechanism, but i'm wondering how can i solve this problem using the same JDK dynamic proxy?
The problem in your code is that you are using the class MyDaoRepository instead of the dao interface. You can cast your proxy to the interface dao but you can not cast it to its implementation. You need to modify your service code to use interfaces:
#Service
public class MyService implements service {
#Autowired
dao myDaoRepository;
#Override
public boolean save( Person person ){
return this.myDaoRepository.save(person);
}
#Override
public boolean delete(Person person){
return this.myDaoRepository.delete(person);
}
}
I need to get the bean from the factory by name.
I wonder if there is a more elegant way to deal with this problem?
My working code now looks like this. This is my interface service and "factory"
public interface GreetingService {
void getGreeting(String name);
}
public interface GreetingServiceFactory {
GreetingService getGreetingService(String region);
}
Implementation greetingService:
#Service
public class EnglishGreetingServiceImpl implements GreetingService {
#Override
public void getGreeting(String name) {
System.out.println("Hello " + name);
}
}
#Service
public class GermanGreetingServiceImpl implements GreetingService {
#Override
public void getGreeting(String name) {
System.out.println("Willkommen " + name);
}
}
Implementation factory:
#Service
public class GreetingServiceFactoryImpl implements GreetingServiceFactory {
private Map<String, GreetingService> greetingBeanMap;
#Autowired
#Qualifier("germanGreetingServiceImpl")
private GreetingService germanGreetingService;
#Autowired
#Qualifier("englishGreetingServiceImpl")
private GreetingService englishGreetingService;
#PostConstruct
public void init () {
greetingBeanMap = new HashMap<>();
greetingBeanMap.put("en", englishGreetingService);
greetingBeanMap.put("de", germanGreetingService);
}
#Override
public GreetingService getGreetingService(String region) {
return greetingBeanMap.get(region);
}
}
Main class with example code where I receive bean after some name
#SpringBootApplication
public class SpringFactoryApplication implements CommandLineRunner {
#Autowired
private GreetingServiceFactory greetingServiceFactory;
public static void main(String[] args) {
SpringApplication.run(SpringFactoryApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
String config1 = "en";
GreetingService english = greetingServiceFactory.getGreetingService(config1);
english.getGreeting("John");
String config2 = "de";
GreetingService deutsch = greetingServiceFactory.getGreetingService(config2);
deutsch.getGreeting("Hans");
}
}
In your above code, this piece of code is completely redundant
#Autowired
#Qualifier("germanGreetingServiceImpl")
private GreetingService germanGreetingService;
#Autowired
#Qualifier("englishGreetingServiceImpl")
private GreetingService englishGreetingService;
#PostConstruct
public void init () {
greetingBeanMap = new HashMap<>();
greetingBeanMap.put("en", englishGreetingService);
greetingBeanMap.put("de", germanGreetingService);
}
this piece of code can be replaced by
#Autowired
private Map<String, GreetingService> greetingBeanMap;
When you declare like this, spring will search for all implementations of GreetingService interface and inject into your map, with the key as the bean name. i.e. the greetingBeanMap will have key's as germanGreetingServiceImpl and englishGreetingServiceImpl and value as the bean's itself.
If you want to make the key's as "en" and "de" instead of bean names, then you can name the beans as "en" and "de". Like this
#Service("en")
public class EnglishGreetingServiceImpl implements GreetingService {
......
}
#Service("de")
public class GermanGreetingServiceImpl implements GreetingService {
......
}
let imagine I have per entity a repository class (spring data jpa) for database access and a service class. The dependencies are managed by spring framework. Every service method does in most cases the same, so there is mainly code duplication:
public class NewsService {
#Inject
private NewsRepository newsRepository;
public void add(News news) {
// do some validation
newsRepository.save(news);
}
}
public class UserService {
#Inject
private UserRepository userRepository;
public void add(User user) {
// do some validation
userRepository.save(user);
}
}
Now i thought about creating an abstract class like this:
public abstract class AbstractService<T> {
private UnknownRepository unknownRepository;
public void add(T entity) {
// do some validation
unknownRepository.save(entity);
}
}
public class NewsService extends AbstractService<News> {
}
public class UserService extends AbstractService<User> {
}
My problem: How can i overwrite the repository used inside the abstract class based on my entities?
You can replace the UnknownRepository field with an abstract method and a type parameter:
// R is the type of the repository
public abstract class AbstractService<T,R extends BaseRepository> {
protected abstract R getRepository();
public void add(T entity) {
getRepository().save(entity);
}
}
And inject the specific repository to the implementations of this class:
public class NewsService extends AbstractService<News, NewsRepository> {
#Inject private NewsRepository newsRepository;
#Override
public NewsRepository getRepository() {
return newsRepository;
}
// the inherited add() method works now
}