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/
Related
Situation -
During the implementation of an Activity tracking system, to improve performance I resort to Caching some repeated DB calls using #Cachable annotation.
The structure looks like this:
An Interface
ActivityCaseService<T>
An Abstract
AbstractActivityCaseImpl<T> implements ActivityCaseService<T>
Concrete classes
LoginActivityCaseImpl extends AbstractActivityCaseImpl<LoginActivityCase>
CallActivityCaseImpl extends AbstractActivityCaseImpl<CallActivityCase>
Based on the type of ActivityCaseType requested, it switches between LoginActivity or CallActivity implementation and executes the methods on them. Have implemented ActivityCaseServiceFactory to get the instance of a class at runtime.
But, during the implementation, #Cachable added on the method gets ignored. I have an intuition that beans returned by ActivityCaseServiceFactory are not Cacheable weaved proxies, that's why annotation is not working, but don't understand the exact issue, and how to rectify if that's the problem!
Reference:
spring.version 4.3.9.RELEASE
#Cachable works perfectly for other services in the same codebase
ActivityCaseServiceFactory
#Service
public class ActivityCaseServiceFactory {
/*ActivityCaseType:Enum*/
private Map<ActivityCaseType, ActivityCaseService<?>> activityCaseTypeVsActivityCaseService = new HashMap<>();
public ActivityCaseServiceFactory(List<ActivityCaseService<?>> abstractActivityCaseServiceImpls) {
activityCaseTypeVsActivityCaseService =
abstractActivityCaseServiceImpls.stream()
.collect(Collectors.toMap(ActivityCaseService::getActivityCaseType, A -> A));
}
public ActivityCaseService<?> getService(ActivityCaseType activityCaseType) {
return activityCaseTypeVsActivityCaseService.get(activityCaseType);
}
}
ActivityCaseService
public interface ActivityCaseService<T> extends BeanInitializer {
ActivityCaseType getActivityCaseType();
/* Method executed based on ActivityCaseType */
List<? extends ActivityBaseCaseDto> getActivityByUserIds(
ActivityInRangeQuery activityInRangeQuery, List<Integer> userIds, Boolean fromCache);
/* Tried to declare here so that execution could be intercepted by AOP Proxy */
Optional<List<T>> findActivityInRangeQuery(
ActivityInRangeQuery activityInRangeQuery, List<Integer> agentIds, Boolean fromCache);
}
AbstractActivityCaseServiceImpl
public abstract class AbstractActivityCaseServiceImpl<T extends ActivityCase> implements ActivityCaseService<T> {
public abstract ActivityCaseType getActivityCaseType();
public abstract List<? extends ActivityBaseCaseDto> getActivityByUserIds(
ActivityInRangeQuery activityInRangeQuery,
List<Integer> userIds,
Boolean fromCache);
public abstract Optional<List<T>> findActivityInRangeQuery(
ActivityInRangeQuery activityInRangeQuery, List<Integer> agentIds, Boolean fromCache);
}
LoginActivityCaseImpl
#Service(value = "LoginActivityService")
public class LoginAbstractActivityCaseServiceImpl extends AbstractActivityCaseServiceImpl<LoginActivityCase> {
#Override
public ActivityCaseType getActivityCaseType() {
return ActivityCaseType.LOGIN;
}
#Override
public List<LoginActivityBaseCaseDto> getActivityByUserIds(
ActivityInRangeQuery activityInRangeQuery, List<Integer> userIds, Boolean fromCache) {
String[]
beanNamesForType =
applicationContext.getBeanNamesForType(ResolvableType.forClassWithGenerics(ActivityCaseService.class,
LoginActivityCase.class));
(List<LoginActivityCase>) applicationContext.getBean(beanNamesForType[0],
ActivityCaseService.class).findActivityInRangeQuery(activityInRangeQuery, agents, fromCache);
/*- More logic to transform List<LoginActivityCase> received above -*/
}
/* ----> #Cacheable not working here <---- */
#Override
#Cacheable(value = CacheNames.ACTIVITY_CACHE,
condition = "#fromCache",
unless = "#result == null")
public Optional<List<LoginActivityCase>> findActivityInRangeQuery(
ActivityInRangeQuery activityInRangeQuery, List<Integer> agentIds, Boolean fromCache) {
/* -- Time taking IO calls -- */
}
}
OtherService
#Autowired
private ActivityCaseServiceFactory activityCaseServiceFactory;
public List<ActivityBaseCaseDto> getActivityForUserAndTeam(/*Params*/) {
return activityCaseServiceFactory.getService(ActivityCaseType.LOGIN)
.getActivityByUserIds(ActivityInRangeQuery.builder().build(),new ArrayList<>(Arrays.asList(1,2)),true);
}
Have been scratching my head for 2 days while searching solution to resolve this issue, but all in vain :). So, before moving to Custom Cache implementation, thought to get help from this amazing StackOverflow community.
What am I doing wrong with #Cachable? And also, open to any criticism/suggestion about how the code is overall structured to implement Activity Tracking.
Adding some screenshots to give more context:
I'm building my first Spring Boot app using JPA and have setup my data repositories and services like this:
#Repository
public interface FooRepository extends JpaRepository<Foo, Long> {
Set<Foo> findAllByActiveInstallationIsNull();
}
Then a CrudService
public interface CrudService<T extends BaseEntity> {
Set<T> findAll();
T findById(Long id);
T save(T object);
void delete(T object);
void deleteById(Long id);
}
along with an example class service interface that extends it
public interface FooService extends CrudService<Foo> {
Set<Foo> findAllAvailable();
Foo getIfAvailable(Long id);
}
an abstract class for service implementations
public abstract class AbstractJpaService<T extends BaseEntity, R extends JpaRepository<T, Long>> implements CrudService<T> {
protected R repository;
public AbstractJpaService(R repository) {
this.repository = repository; }
#Override
public Set<T> findAll() {
return new HashSet<>(repository.findAll()); }
#Override
public T findById(Long id) {
return repository.findById(id).orElse(null); }
#Override
public T save(T object) {
return repository.save(object); }
#Override
public void delete(T object) {
repository.delete(object); }
#Override
public void deleteById(Long id) {
repository.deleteById(id); }
}
and finally an example of an actual service class that extends the above-mentioned one:
#Service
#Transactional
public class FooJpaService extends AbstractJpaService<Foo, FooRepository> implements FooService {
public FooJpaService(FooRepository repository) {
super(repository);
}
///
}
I wrote some service layer logic, controllers and once I was happy with the first iteration I've done some postman testing that worked without a hitch.
Then I took a step back and started writing some unit tests for my service classes only to realize that while findAll() in my services returns Set as I intended, the JpaRepository methods and by extension my own repos give List.
#Test
void findAll() {
Set<Foo> returnFooSet = new HashSet<>();
returnFooSet.add(new Foo(boo, 1d, 2d));
returnFooSet.add(new Foo(baz, 3d, 4d));
when(fooRepository.findAll()).thenReturn(returnFooSet);
Set<Foo> foos = service.findAll();
assertNotNull(foos);
assertEquals(2, foos.size());
}
resulting in thenReturn() method expecting a List.
Sorry for the wall of code, but I'm pretty new at this and very much confused so figured I'll provide excessive context even if most could have been assumed, since my newbie implementations may be weird and faulty.
So what gives?
I've read about the benefits of using Sets in JPA and most of the code examples I've seen use them.
My own findAllByArgument methods with Set returns like the ones you see in the repository have been working just fine, so I assume nothing stops me from overriding basic FindAll() methods in all of my repos (since CrudRepository seems to have just Iterable there), but that seems... off?
Should I be using Sets with JPA? What are good practices in this case?
I believe the only rule of thumb regarding List or Set in JPA world (with Hibernate under the hood) is to always use Set on a #ManyToMany relationship and never List.
Other than that I am not aware of anything else. Still, I can guess that maybe Set is better in terms of performance since it is unordered while List is ordered. Given that JpaRepository has a method that returns List this eventually better performance might not be relevant enough.
i have a few DAOs in my app which access a database for CRUD operations. Lets say there News, weather and , sports DAO. So im confused on how many Repositories i would need. should i just use one repository say DataRepository and let me hold my database and all dao's. and encapsulate methods for the CRUD operations in it ? or should each DAO have its own repository ?
I mean a repository should return only data objects that the calling layer understands. so its like a encapsulation over the DAOs but im not sure if i should create one per DAO or just have one repo per app, etc.
If you read this article we begin to understand that the pattern is over engineered or over abstracted. Its turned into hiding detail vs minimizing query statements.
But it seems There should be a Repo per DAO as the interface itself looks like this:
interface Repository<T> {
void add(T item);
void remove(Specification specification);
List<T> query(Specification specification);
}
where T can be the type/table of data DAO accesses. Just need clarification now. Can you imagine i have 30 different types, so then i need 30 different Repo implementations. this is ridiculous. It seems the repository pattern itself is like a DAO, no different. im so confused.
I am not sure this is what all you looking for but In my application I am using described DAO pattern with Spring
So im confused on how many Repositories i would need.
IMHO you will need at least single Repository for each entity as they lead to simple design but since you are making them generic and they are up in hierarchy, can be used simply with child classes/interfaces
Below is the example
Interface to define all basic methods that to use commonly
public interface GenericDAO<T, ID extends Serializable> {
T findById(ID id, LockModeType lock);
void save(T entity);
T update(T entity);
List<T> findAll();
}
Generic Implementation
public abstract class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {
#PersistenceContext
protected EntityManager em;
private final Class<T> entityClass;
public GenericDAOImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
#Override
public T findById(ID id, LockModeType lock) {
return em.find(entityClass, id, lock);
}
#Override
public void save(T entity) {
em.persist(entity);
}
#Override
public T update(T entity) {
return em.merge(entity);
}
#Override
public List<T> findAll() {
CriteriaQuery<T> c = em.getCriteriaBuilder().createQuery(entityClass);
c.select(c.from(entityClass));
return em.createQuery(c).getResultList();
}
.
.
.
}
Foo class
#Entity
public class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String text;
}
Foo Repositiry
public interface FooRepositiry extends GenericDAO<Foo, Long> {
Foo findTextById(Long id);
}
Implemented Foo Repositiry
#Transactional
#Repository
public class FooRepoImpl extends GenericDAOImpl<Foo, Long> implements FooRepositiry {
public FooRepoImpl() {
super(Foo.class);
}
#Override
public Foo findTextById(Long id) {
CriteriaQuery<Foo> c = em.getCriteriaBuilder().createQuery(Foo.class);
// .
// .
// .
return em.createQuery(c).getSingleResult();
}
}
Same for Bar class
#Transactional
#Repository
public class BarRepoImpl extends GenericDAOImpl<Bar, Long> implements BarRepo {
public BarRepoImpl() {
super(Bar.class);
}
#Override
public List<Bar> findAllBarWithText(String text) {
CriteriaQuery<Bar> c = em.getCriteriaBuilder().createQuery(Bar.class);
return em.createQuery(c).getResultList();
}
}
Here this generic implementation needs two things to work: an EntityManager and an
entity class. A subclass must provide the entity class as a constructor argument. EntityManager is provided by using PersistenceContext or you can use getter-setter methods for the same. Since GenericDAOImpl is abstract threfore you cannot use it directly but Indirectly and most of the commnoly used methods are generic and up in hierarchy which makes them Ideal candidate to be reused.
You can read more about this from book Java Persistence with Hibernate 2nd Edition
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);
}
}