Hibernate пагинация с AOP pointcuts
Существует ли какой-либо известный подход к нумерации страниц с помощью аспектно-ориентированных аннотаций (или чего-либо еще, что делает работу) с помощью pointcut для идентификации Criteria
в любом данном методе и применять к нему setFirstResults
а также setMaxResults
Методы API?
Например, я хотел бы применить нумерацию страниц в моей спящей GenericDao
реализация:
@Paginate
public List<T> filter(Set<Criterion> filter, Map<String, String> alias){
Criteria criteria = session.createCriteria(type.class);
fillCriteria(criteria, filter, alias);
return criteria.list();
}
И @Paginate
аннотация будет применяться setFirstResults
а также setMaxResults
на criteria.list()
вызов. Это возможно?
Замечания: @Paginate
это пример того, что я хотел бы использовать.
1 ответ
Да, вы можете сделать это через AspectJ.
Вот самосогласованный, автономный пример кода. Вы можете просто скопировать и вставить классы и аспект и запустить его. Я не использую оригинальные классы Hibernate, но некоторые фиктивные замены, потому что я не пользователь Hibernate, и я также хочу сделать это универсальным ответом:
Фальшивые, похожие на hibernate интерфейсы и классы:
package de.scrum_master.app;
public interface Criterion {}
package de.scrum_master.app;
public class MyCriterion implements Criterion {
private String criterion;
public MyCriterion(String criterion) {
this.criterion = criterion;
}
@Override
public String toString() {
return "MyCriterion [criterion=" + criterion + "]";
}
}
package de.scrum_master.app;
import java.util.List;
public interface Criteria {
Criteria add(Criterion criterion);
List list();
Criteria setFirstResult(int firstResult);
Criteria setMaxResults(int maxResults);
}
package de.scrum_master.app;
import java.util.LinkedList;
import java.util.List;
public class MyCriteria implements Criteria {
private List<Criterion> criteria = new LinkedList<>();
@Override
public Criteria add(Criterion criterion) {
criteria.add(criterion);
return this;
}
@Override
public List list() {
return new LinkedList();
}
@Override
public Criteria setFirstResult(int firstResult) {
add(new MyCriterion("first result " + firstResult));
return this;
}
@Override
public Criteria setMaxResults(int maxResults) {
add(new MyCriterion("max results " + maxResults));
return this;
}
@Override
public String toString() {
return "MyCriteria [criteria=" + criteria + "]";
}
}
Как видите, методы setFirstResult(..)
а также setMaxResults(..)
добавить специальные критерии через add(..)
на внутренний список. Я просто сделал это, чтобы позже проиллюстрировать эффект аспекта.
Разметка страницы:
package de.scrum_master.app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Paginate {}
Приложение для водителя:
package de.scrum_master.app;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Application {
@Paginate
public List filter(Set<Criterion> filter, Map<String, String> alias) {
Criteria criteria = new MyCriteria();
for (Criterion criterion : filter)
criteria.add(criterion);
return criteria.list();
}
public static void main(String[] args) {
Set<Criterion> filterCriteria = new HashSet<>();
filterCriteria.add(new MyCriterion("where"));
filterCriteria.add(new MyCriterion("group by"));
new Application().filter(filterCriteria, null);
}
}
Приложение содержит метод, аннотированный @Paginate
, делая подобные вещи, как ваш пример кода. Это не вызывает никаких методов нумерации страниц все же. Это будет сделано по следующему аспекту.
Нумерация страниц:
package de.scrum_master.aspect;
import java.util.List;
import de.scrum_master.app.Paginate;
import de.scrum_master.app.Criteria;
public aspect PaginationAspect {
Object around(Criteria criteria) :
call(public List Criteria+.list()) &&
cflow(execution(@Paginate * *(..))) &&
target(criteria)
{
System.out.println(thisJoinPoint);
System.out.println("Original criteria: " + criteria);
criteria.setFirstResult(5);
criteria.setMaxResults(10);
System.out.println("Modified criteria: " + criteria);
return proceed(criteria);
}
}
Pointcut перехватывает вызовы Criteria+.list()
(+
включает подклассы), но только когда выдается в потоке управления (cflow()
) любых исполняемых методов, аннотированных @Paginate
, Цель вызова связана с параметром Criteria criteria
чтобы использовать его в методе совета, привязанном к этому pointcut. Нам нужна ссылка на цель вызова, потому что мы хотим вызвать методы нумерации страниц на ней. Это то, что делает совет, и это ясно иллюстрируется выводом консоли.
Консольный вывод:
call(List de.scrum_master.app.Criteria.list())
Original criteria: MyCriteria [criteria=[MyCriterion [criterion=group by], MyCriterion [criterion=where]]]
Modified criteria: MyCriteria [criteria=[MyCriterion [criterion=group by], MyCriterion [criterion=where], MyCriterion [criterion=first result 5], MyCriterion [criterion=max results 10]]]
Наслаждайтесь!