我正在为我的java项目开发一个分页系统,我想让它适用于我的各种JPA模型。
问题(据我所知)是,如果我使用泛型,我将不得不以某种方式投射返回的最终值来处理它。我怎么能避免这种情况?
到目前为止,这是我的代码(绝对不是通用的!):
public interface Paginator {
public void setLimit(Integer limit);
public Page page(Integer page);
}
public class PicturesPaginator implements Paginator {
private Integer limit = 10;
private JPAQuery query;
private Long quantity;
public PicturesPaginator(String query, Object... params) {
this.query = Picture.find(query, params);
this.quantity = Picture.count(query, params);
}
@Override
public void setLimit(Integer limit) {
this.limit = limit;
}
@Override
public PicturesPage page(Integer page) {
if (page == null)
page = 1;
List<Picture> pictures = query.fetch(page, limit);
return new PicturesPage(pictures, quantity, page, limit);
}
}
public abstract class Page {
protected List<Picture> pictures;
protected Long quantity;
protected Integer page;
protected Integer limit;
public List<Picture> list() {
return pictures;
}
public Long count() {
return quantity;
}
public boolean hasNext() {
return (page * limit > quantity);
}
public boolean hasPrevious() {
return (page != 1);
}
public boolean hasOtherPages() {
return (hasNext() || hasPrevious());
}
public Integer nextPageNumber() {
if (!hasNext())
return null;
return (page + 1);
}
public Integer previousPageNumber() {
if (!hasPrevious())
return null;
return (page - 1);
}
public Integer currentPageNumber() {
return page;
}
}
public class PicturesPage extends Page {
public PicturesPage(List<Picture> pictures, Long quantity, Integer page, Integer limit) {
this.pictures = pictures;
this.quantity = quantity;
this.page = page;
this.limit = limit;
}
}
我想摆脱那些PicturesPaginator
和PicturesPage
并使其成为通用的,但抽象类Page中的list()
方法将返回一个通用列表({{1} }或List<T>
因为我在这里使用Play)。
我期望的是这个List<GenericModel>
方法返回正确的List,在我的情况下又称list()
。这可能吗?
注意:我现在在Play中有一个分页模块!框架,我的问题主要是为了更多地了解java :))
非常感谢你的帮助,我真的很感激!
答案 0 :(得分:3)
您可以查看我的Play - Pagination模块的源代码,看看我是如何处理这类事情的。我把source on github。
你想要做的是使页面也是通用的,也可能是非抽象的:
public class Page<T> {
public List<T> list() {}
}
而不是PicturePage,你可以这样做:
new Page<Picture>()
Paginator界面也需要通用化:
public interface Paginator {
public Page<T> page(Integer page);
}
由于您在Picture类上调用方法,因此Generifying PicturesPaginator会更难。 Java的泛型实现在运行时擦除类型,因此您必须处理类型标记和反射。
public abstract class GenericPaginator<T> {
public GenericPaginator() {
Class<T> typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// use reflection to invoke the finders methods
}
}
public class PicturesPaginator extends GenericPaginator<Picture> {}
答案 1 :(得分:1)
我期望这个list()方法返回正确的List, 在我的案例中也称列表。这可能吗?
这不仅仅是可能的,如果您正确使用泛型,那就是您自动获得的。如果你宣布
public class Page<T extends GenericModel>{
protected List<T> items;
public List<T> list() {
return items;
}
}
并像这样使用它:
page = new Page<Picture>();
然后page.list()
实际上将返回List<Picture>
,因为T
是一个类型参数,当Page
时由具体类型替换声明了。
答案 2 :(得分:1)
如果我理解正确,以下内容可能有所帮助:
让Pace变得通用。转
public abstract class Page {
protected List<Picture> pictures;
public List<Picture> list() {
return pictures;
}
为:
public abstract class Page<Element> {
protected List<Element> elements;
public List<Element> list() {
return elements;
}
比使图片页面更加具体:
public class PicturesPage extends Page<Picture> {
答案 3 :(得分:1)
我不确定这是否是您所需要的,但您可以将Page类转换为:
public abstract class Page<T> {
protected List<T> pictures;
protected Long quantity;
protected Integer page;
protected Integer limit;
public List<T> list() {
return pictures;
}
public Long count() {
return quantity;
}
public boolean hasNext() {
return (page * limit > quantity);
}
public boolean hasPrevious() {
return (page != 1);
}
public boolean hasOtherPages() {
return (hasNext() || hasPrevious());
}
public Integer nextPageNumber() {
if (!hasNext())
return null;
return (page + 1);
}
public Integer previousPageNumber() {
if (!hasPrevious())
return null;
return (page - 1);
}
public Integer currentPageNumber() {
return page;
}
答案 4 :(得分:1)
如果我理解正确,那么在这里引入泛型的问题就是这样的行:
this.query = Picture.find(query, params);
AFAIK你不能直接在泛型类型上调用静态方法,所以你必须在这里使用反射。在这种情况下,您可能必须将参数类型的类作为参数传递(或者从反射数据中获取它(如果存在)),找到要调用的方法并调用它。
这是这样的:
Class<T> clazz;
public Paginator (Class<T> clazz) {
this.clazz = clazz;
//note that you need to handle exceptions, I'll leave them out for brevity
Method findMethod = clazz.getMethod("find", String.class, Array.class );
this.query = findMethod.invoke(null, query, params);
}
修改的
作为替代方案,将“finder”对象传递给通用Paginator
,并使其实现提供find(...)
和count(...)
方法的接口:
interface Finder<T> {
JPAQuery find( String query, Object... params);
Long count( String query, Object... params);
}
class Paginator<T, F extends Finder<T>> {
public Paginator(F finder, String query, Object... params) {
this.query = finder.find(query, params);
...
}
...
}