I'm using room persistence library to update the database. I'm stuck at a point where I want to fetch the id of recently inserted record.
I know that using long as the return type for the insert method returns the id. But I access this Dao method through a viewmodel.
My DAO method is as follows:
//MyDao
#Insert
long insert(RecordItem record);
This method is accessed from a repository by doing this:
//MyRepository
public class MyRepository {
private MyDao myDao;
public MyRepository(#NonNull Application application) {
MainDatabase mainDatabase = MainDatabase.getInstance(application);
myDao = mainDatabase.myDao();
}
public void insert(RecordItem record) {
MainDatabase.dbWriteExecutor.execute(() -> {
myDao.insert(record);
});
}
}
And the repository method is called from viewmodel as follows:
//MyViewModel
public void insert(RecordItem record) {
repository.insert(record);
}
And finally the viewmodel method as:
//MyActivity
myViewModel.insert(record);
My problem is, I don't know how I can get long returned through a viewmodel method. I tried doing this in repository
//MyRepository
public class MyRepository {
private MyDao myDao;
private long id;
public MyRepository(#NonNull Application application) {
MainDatabase mainDatabase = MainDatabase.getInstance(application);
myDao = mainDatabase.myDao();
}
public long insert(RecordItem record) {
MainDatabase.dbWriteExecutor.execute(() -> {
id = myDao.insert(record);
});
return id;
}
}
and subsequent changes to viewmodel method as well.
However, it returns 0, which I suppose happens since the insert method is executed on a different thread and id is returned as soon as the statement is reached(correct me if I'm wrong).
Thanks in advance.
You can approach following solution for your issue:
Create a Callback interface as below:
public interface DbInsertCallback {
void onInsert(long insertedItemId);
}
Then use this interface on your repository insert(RecordItem record) method like below usage:
public class MyRepository {
// ... Some repo code ...
public void insert(RecordItem record, DbInsertCallback callback) {
MainDatabase.dbWriteExecutor.execute(() -> {
long id = myDao.insert(record);
callback.onInsert(id);
});
}
// ... Rest of repo code ...
}
And also make necessary changes on caller site (I.e. ViewModel & Activity) to provide object of this callback class as parameter as well. To do the implementation of this interface, you can either create object of that interface along with implementation or else pass it contextually like providing this.
You can also use RxJava for this problem, where the insert method will return Single<Long>.
#Insert
Single<long> insert(RecordItem item)
Then when calling insert you call subscribe to get the returning id or use flatMap for any further actions using RxJava.
myDao.insert(record).subscribeWith(new DisposableSingleObserver<long>() {
#Override
public void onSuccess(long id) {
// handle the id
}
#Override
public void onError(Throwable e) {
// handle the error case
}
}
I suggest you to take a look at RxJava further down the line since it makes asynchronous programming much more natural and easier to work with and Room also implements it out of the box.
Related
I working on writing tests for a crud application. I need to test the service and repository for Delete and Update statements. How would I go about mocking the repository for delete and update since they won't be returning data?
For example:
#Override
public void makeUserActive(long userId) {
try {
Optional<UserEntity> userEntityList = usersJpaRepository.findById(userId);
UserEntity userEntity = userEntityList.get();
userEntity.setIsActive(1);
usersJpaRepository.save(userEntity);
} catch (Exception e) {
logger.error("Cant make active user", e);
}
}
How do i test the service that mocks this repository and also the repository itself since it wont be returning a value
The question is what is the thing you want to be tested?
If you would like to test your repository you can achieve this by using Springs #DataJpaTest. see Integration Testing With #DataJpaTest
If you would like to test the logic inside your makeUserActive-Method you must make sure to mock your repository.
Assuming the service which contains your makeUserActive-Method looks something like this:
public class UserService{
private final UsersJpaRepository usersJpaRepository;
public UserService(UsersJpaRepository usersJpaRepository) {
this.usersJpaRepository = usersJpaRepository;
}
public void makeUserActive(long userId){
// your code from your question
}
}
You could write your Unit Test like this:
#Test
void makeUserActiveTest(){
UsersJpaRepository repository = new InMemoryUsersJpaRepository();
UserEntity user = new UserEntity();
user = repository.save(user);
UserService service = new UserService(repository);
service.makeUserActive(user.getId());
Optional<UserEntity> activatedUser = repository.findById(user.getId());
assertTrue(activatedUser.isPresent());
assertEquals(1, activatedUser.get().isActive());
}
The InMemoryUsersJpaRepository is a self written Mock which will store all data in an internal Map. The code could look something like this:
public class InMemoryUsersJpaRepository extends UsersJpaRepository {
private Map<Long, UserEntity> users = new HashMap<>();
private Long idCounter = 1L;
#Override
public UserEntity save(UserEntity user) {
if(user.getId() == null){
user.setId(idCounter);
idCounter++;
}
users.put(user.getId(), user);
return user;
}
#Override
public Optional<UserEntity> findById(long userId) {
return Optional.of(users.get(userId));
}
}
This way you will test the logic of your makeUserActive-Method which is currently to simply set the isActivated Flag on you UserEntity.
Also I would like to warn you about the answer of Mensur Qulami.
The Code in his answer will lead to a passing test but I'am pretty sure it does not test the thing you want to be tested.
You should always test the expected and observable behaviour of your method.
In your case this would be the isActivated Flag that should be 1.
The fact that your makeUserActive-Method calls the findById and save Method of the UsersJpaRepository is a mere implementation detail and the testing of those generally lead to brittle tests.
For the methods returning void, you can simply verify that they have been called. Here's an example, that mocks both an object returning method and void returning method.
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
private Repository repository;
#InjectMocks
private Service service; // assume that this is your class
#Test
void testMakeUserActive() {
// given:
final UserEntity userEntity = new UserEntity();
// mocks:
when(repository.findById(1)).thenReturn(Optional.of(userEntity));
// when:
service.makeUserActive(1);
// then:
verify(repository).findById(1);
verify(repository).save(userEntity);
}
}
In my current spring setup i would like to implement a slightly different architecture, here is my setup:
I have a "base" DAO interface, which lists all CRUD operations:
public interface BaseDao {
public boolean create(Object obj);
public List<Object> read();
public boolean update(Object obj);
public boolean delete(Object obj);
}
Next i have "specific" DAO interface, which extends from the "base" one:
public interface ArticleDao extends BaseDao {
public List<Article> getArticlesByAttribute(String attribute);
}
And finally, the Repository, which implements the interface:
public class ArticleDaoImpl implements ArticleDao {
public boolean create(Article article) {
// code
}
public List<Article> read() {
// code
}
public boolean update(Article article) {
// code
}
public boolean delete(Article article) {
// code
}
public List<Article> getArticlesByAttribute(String attribute) {
// code
}
}
So the idea is simple:
I want every Repository to implement all crud operations + "the methods from the specific dao-interface"
But i get the following error:
ArticleDaoImpl is not abstract and does not override
abstract method delete(java.lang.Object) in BaseDao
etc..
So this is probably because i defined Object as a parameter in the interface and "Article" as a parameter in the actual implementation..
Anybody got the idea how i can follow this pattern correctly?
Should i consider working with generics?
Thanks and Greetings
No. You should work with Spring Data JPA/MongoDB etc. It will make MOST of your boilerplate code go away. Seriously - forget about DAO and go with Spring Data JPA: https://spring.io/guides/gs/accessing-data-jpa/
i'm developping a small buissness application and i need to know how to pass complex logic to indicate what Clients to fetch from the database
Here is my ClientDAO class :
public class ClientDAO {
public void save(Client clt) {
}
public Client find(int id) {
return null;
}
public void update(Client clt) {
}
public void delete(Client clt) {
}
}
This is a normal CRUD class, but if i need to fetch all client FROM date xx to yy, i need to add another find method overloaded?? and if i want to find all Client That have an age bettwen xx and yy i will another find function??
that don't seem a good design
i know what i'm doing is wrong, i want to know the right way to do it.
PS : i'm going to use JDBC without any ORM
When not using an ORM, creating multiple methods for querying the data is the right way to go. The purpose of the DAO is to totally isolate the rest of the application from the database access logic, meaning the DAO is the only class that knows the table and column names.
Now, for the advanced topic: If the application will need to query the table using a variety of criterias, creating a new method for each combination would be cumbersome, and having too many parameters on a single method wouldn't be right either.
For this kind of problem, the builder pattern is a good solution. Your DAO could implement a filter() method that returns a builder object, with good criteria methods and a final execute() method:
public class ClientDAO {
public static final class Filter {
Filter() {
// code not shown for brevity
}
public Filter withNameLike(String name) {
// code not shown for brevity
}
public Filter createdAfter(Date fromDate) {
// code not shown for brevity
}
public Filter createdBefore(Date fromDate) {
// code not shown for brevity
}
public List<Client> query() {
// code not shown for brevity
}
}
public static Filter filter() {
return new Filter();
}
}
It can then be used like:
List<Client> clients = ClientDAO.filter()
.withNameLike("%John%")
.createdAfter(fromDate)
.query();
I am working on a JavaEE project. All/Most classes i am working on reside on the data base. There fore all must support creating, editing and deleting a database entry.
I don't want to use any frameworks.I planed to execute the queries using the traditional prepared statements.
Currently I implemented it as follows
public interface Entity{
public boolean create(Entity e);//executes a query with the objects fields
public boolean change(Entity e);//executes a query to update fields of the entity
public boolean delete(Entity e);//deletes the entry
public ArrayList<Entity> getAll();//retrives all the entries in the database
}
Now my question
I'm i doing it right?
If a class inherites form a class that implements this interface how should it handel the methods? Should it override or call the super and add more code to handle more fields
Should i create another utility class to send the queries or is it ok if i add the database actions in the same class?
Appreciate in advance!
You are saying, that you are working on a Java EE project - so why don't use the APIs provided by it? There's a simple recommendation: Use JPA for it and only don't use prepared statements for CRUD operations of Java objects and don't reinvent an Entity which you already have at hand, together with an EntityManager doing all the operations you need on it.
What you are trying to implement is called a Data Access Object interface. It is in fact a well known and good practice, but judging from your interface name you want to use the CRUD methods directly whitin your entities and is not a good idea.
You should create an interface, say
public interface BookDAO{
public Book create(Book book);
public List<Book> read();
public Book update(Book book);
public Book delete(Book book);
}
with the CRUD methods. Then you can implement such interface depending on your database, say
class MySqlBookDAOImpl implements BookDAO{
private Connection conn;
private Connection getConnection(){
if(conn==null)
conn = mySqlConnectionPool.getConnection();
return conn;
};
#Override
public Book create(Book book){
Connection conn = getConnection();
String query = "INSERT... "
};
#Override
public List<Book> read(){
Connection conn = getConnection();
String query = "SELECT... "
};
#Override
public Book update(Book book){
Connection conn = getConnection();
String query = "UPDATE... "
};
#Override
public Book delete(Book book){
Connection conn = getConnection();
String query = "DELETE... "
};
}
and implement the abstract methods to communicate with the database using the correct database driver (depends also from your connection policies).
Regarding your other 2 questions:
When implementing a method from an interface you always ovveride it. You can't call a super method just because there is no super method. You call super only when you extend and override the method from the parent class.
The DAO should take care of sending the queries to the database and the DAO is going to create them within its methods.
Why are you so reluctant to use a framework or built in API? There are really good ones that can spare you a lot of work (like JPA).
You should distinguish entities and DAOs. Entities are the data, DAOs interact with the DB.
For example:
public interface Entity<K extends Serializable> {
K getId();
}
public interface Dao<K extends Serializable, E extends Entity<K>> {
E create(E entity);
E update(E entity);
E delete(E entity);
E get(K id);
List<E> getAll();
}
Then, implementations:
public class User implements Entity<Integer> {
private Integer id;
public User(Integer id) {
this.id = id;
}
#Override
public Integer getId() {
return id;
}
}
public class UserDao implements Dao<Integer, User> {
#Override
public User create(User entity) {
// build query
}
#Override
public User update(User entity) {
// build query
}
#Override
public User delete(User entity) {
// build query
}
#Override
public User get(Integer id) {
// build query
}
#Override
public List<User> getAll() {
// build query
}
}
This can be improved by having a BaseDao abstract class for example, since DAOs will have common code for sure.
Actually I can see you are missing a very basic operation wchich is acceessing objects:
public boolean read(Entity e);
You should also reconsider your class name to have a more relevant one (what this class is intended to do) since naming it as Entity gives the allure of a bean entity not a data access interface layer. Something like CommonDao:
public interface CommonDao {
//...
}
This class can be extended following your Entity type.
You may also need to revise your method signatures, e.g. deleting an entity should only need its identifier.
Update your class also to use Java Generics which will let you gain in reusability and make your class accept any entity type:
public interface CommonDao<T> {
T create(T entity);
//...
}
I highly recommand #sp00m solution.
I have a working "request factory" example and i want to refactor it, so that i can move the generic methods like "persist()" and "remove()" out of the domain object into a generic locator. Currently i have the following (working) code:
A generic super class that holds the id and the version for all domain objects:
#MappedSuperclass
public class EntityBase {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Version
#Column(name = "version")
private Integer version;
// setter & getter
}
A domain object. It has the persist() and remove()-methods, which i want to refactore out of the class:
#Entity
#Table(name = "article")
public class Article extends EntityBase{
public static Article findArticle(Long id) {
//find article
}
public void persist() {
// persist
}
public void remove() {
// remove
}
}
A proxy object for the domain object:
#ProxyFor(value = Article.class)
public interface ArticleProxy extends EntityProxy {
// some getter and setters
}
The request object for my domain object:
#Service(value = Article.class)
public interface ArticleRequest extends RequestContext {
Request<ArticleProxy> findArticle(Long id);
InstanceRequest<ArticleProxy, Void> persist();
InstanceRequest<ArticleProxy, Void> remove();
}
My request factory:
public interface MyRequestFactory extends RequestFactory {
ArticleRequest articleRequest();
}
---------------------------------------
Now my refactored code that is not working anymore:
I removed the persist() and remove()-method out of my domain object:
#Entity
#Table(name = "article")
public class Article extends EntityBase{
public static Article findArticle(Long id) {
//find article
}
}
I created my locator like this and added the methods "remove()" and "persist()" here (alongside the other default methods):
public class EntityLocator extends Locator<EntityBase, Long> {
#Override
public EntityBase create(Class<? extends EntityBase> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
#Override
public EntityBase find(Class<? extends EntityBase> clazz, Long id) {
return null;
}
#Override
public Class<EntityBase> getDomainType() {
return null;
}
#Override
public Long getId(EntityBase domainObject) {
return null;
}
#Override
public Class<Long> getIdType() {
return null;
}
#Override
public Object getVersion(EntityBase domainObject) {
return null;
}
public void persist(EntityBase domainObject){
// persist something
}
public void remove(EntityBase domainObject){
// remove
}
}
My proxy object is linked to the locator (locator=EntityLocator.class):
#ProxyFor(value = Article.class, locator=EntityLocator.class)
public interface ArticleProxy extends EntityProxy {
// getter and setters here
}
My new Request object looks like this. I made the "InstanceRequests" to "Requests", changed return types and parameter according to my new methods in the locator:
#Service(value = Article.class)
public interface ArticleRequest extends RequestContext {
Request<ArticleProxy> findArticle(Long id);
Request<Void> persist(ArticleProxy article);
Request<Void> remove(ArticleProxy article);
}
But now i get the error "Could not find domain method similar to java.lang.Void persist()" for the persist() and remove()-method. Why doesn't the lookup in the EntityLocator work? Do i need a ServiceLocator? I did not fully understand the google tutorial and the linked example is not available anymore.
I had the same question as you. The guide on GWTProject.org (http://www.gwtproject.org/doc/latest/DevGuideRequestFactory.html) is not very clear on how to correctly implement this, although it is written between the lines.
The following tutorial made the solution clear to me: http://cleancodematters.com/2011/06/04/tutorial-gwt-request-factory-part-i/
For me the use of the term DAO obfuscated things. I'm not going to use the DAO pattern. That's what my transparent persistence layer is for. However, the use of the Locator requires an extra class to put the persist, remove and findX methods in. They call it a Data Access Object (which it is, actually), I'd rather call it the Manager.
tl;dr
The methods you're trying to put in the Locator don't go there. You need an extra class (call it a DAO or a Manager).
Use the DAO/Manager as service in your RequestContext
I don't think you can place the persist and remove methods in the locator. The documentation doesn't suggest you can add arbitrary methods to the locator interface and reference them from the client. If you just want to avoid duplicating the persist and remove methods in every entity class then you can put them in your EntityBase class. I've done this and it works nicely.
If you also want to avoid repeating the functions in each of your request interfaces, you can make a generic base class Request like so:
#SkipInterfaceValidation
public interface BaseEntityRequest<P extends EntityProxy> extends RequestContext {
InstanceRequest<P, Void> persist();
InstanceRequest<P, Void> remove();
}
and use it like so:
public interface ArticleRequest extends BaseEntityRequest<ArticleRequest> {
...
}
Although it makes sense that persist() and remove() were in the Locator, so as the entity was completely agnostic about the persistence layer, this is not supported by current RF api. As consequence you have to deal with that adding those methods to your BaseEntity and figuring out a way to call the persist method in your locator.
I think you could open a gwt issue requiring this feature though.
Another way to avoid having certain methods in your entities, is to use ValueProxy insteadof EntityProxy, but in this case you have to provide methods to save/delete those objects from the client.
Your interface ArticleRequest isn't configured properly. You need correct it like this.
#Service(value = SentenceServiceImpl.class, locator = SpringServiceLocator.class)
public interface SentenceServiceRequest extends RequestContext {
Request<List<SentenceProxy>> getSentences();
Request<Void> saveOrUpdate(SentenceProxy sentence);
}
Locator:
public class SpringServiceLocator implements ServiceLocator {
public Object getInstance(Class<?> clazz) {
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestFactoryServlet.getThreadLocalServletContext());
return context.getBean(clazz);
}
}